Skip to content

Commit

Permalink
Merge pull request #2610 from HasiniSama/shared-app-public-client
Browse files Browse the repository at this point in the history
Inherit isPublicClient property from parent application to the shared application
  • Loading branch information
SujanSanjula96 authored Nov 6, 2024
2 parents 69881de + a89695a commit b069af4
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2019-2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -259,27 +259,44 @@ public OAuthConsumerAppDTO getOAuthApplicationData(String consumerKey, String te
/**
* Get OAuth application data by the application name.
*
* @param appName OAuth application name
* @return <code>OAuthConsumerAppDTO</code> with application information
* @param appName OAuth application name.
* @return <code>OAuthConsumerAppDTO</code> with application information.
* @throws IdentityOAuthAdminException Error when reading application information from persistence store.
*/
public OAuthConsumerAppDTO getOAuthApplicationDataByAppName(String appName) throws IdentityOAuthAdminException {

int tenantID = CarbonContext.getThreadLocalCarbonContext().getTenantId();
return getOAuthApplicationDataByAppName(appName, tenantID);
}

/**
* Get OAuth application data by the application name and tenant ID.
*
* @param appName OAuth application name.
* @param tenantID Tenant ID associated with the OAuth application.
* @return <code>OAuthConsumerAppDTO</code> with application information.
* @throws IdentityOAuthAdminException Error when reading application information from persistence store.
*/
public OAuthConsumerAppDTO getOAuthApplicationDataByAppName(String appName, int tenantID)
throws IdentityOAuthAdminException {

OAuthConsumerAppDTO dto;
OAuthAppDAO dao = new OAuthAppDAO();
try {
OAuthAppDO app = dao.getAppInformationByAppName(appName);
OAuthAppDO app = dao.getAppInformationByAppName(appName, tenantID);
if (app != null) {
dto = OAuthUtil.buildConsumerAppDTO(app);
} else {
dto = new OAuthConsumerAppDTO();
}
return dto;
} catch (InvalidOAuthClientException e) {
String msg = "Cannot find a valid OAuth client with application name: " + appName;
String msg = "Cannot find a valid OAuth client with application name: " + appName
+ " in tenant: " + tenantID;
throw handleClientError(INVALID_OAUTH_CLIENT, msg);
} catch (IdentityOAuth2Exception e) {
throw handleError("Error while retrieving the app information by app name: " + appName, e);
throw handleError("Error while retrieving the app information by app name: " + appName
+ " in tenant: " + tenantID, e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,12 +674,18 @@ public OAuthAppDO[] getAppsForConsumerKey(String consumerKey)
return oauthAppList.toArray(new OAuthAppDO[oauthAppList.size()]);
}

public OAuthAppDO getAppInformationByAppName(String appName) throws
InvalidOAuthClientException, IdentityOAuth2Exception {
OAuthAppDO oauthApp;
public OAuthAppDO getAppInformationByAppName(String appName)
throws InvalidOAuthClientException, IdentityOAuth2Exception {

int tenantID = CarbonContext.getThreadLocalCarbonContext().getTenantId();
return getAppInformationByAppName(appName, tenantID);
}

public OAuthAppDO getAppInformationByAppName(String appName, int tenantID)
throws InvalidOAuthClientException, IdentityOAuth2Exception {

OAuthAppDO oauthApp;
try (Connection connection = IdentityDatabaseUtil.getDBConnection(false)) {
int tenantID = CarbonContext.getThreadLocalCarbonContext().getTenantId();
String sqlQuery = SQLQueries.OAuthAppDAOSQLQueries.GET_APP_INFO_BY_APP_NAME_WITH_PKCE;

try (PreparedStatement prepStmt = connection.prepareStatement(sqlQuery)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2018-2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand All @@ -22,11 +22,17 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.oltu.oauth2.common.OAuth;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException;
import org.wso2.carbon.identity.oauth.IdentityOAuthAdminException;
import org.wso2.carbon.identity.oauth.common.OAuthConstants;
import org.wso2.carbon.identity.oauth.common.exception.InvalidOAuthClientException;
import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration;
import org.wso2.carbon.identity.oauth.dao.OAuthAppDO;
import org.wso2.carbon.identity.oauth.dto.OAuthConsumerAppDTO;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext;
import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder;
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;

import java.util.List;
Expand Down Expand Up @@ -109,7 +115,7 @@ public boolean canAuthenticate(HttpServletRequest request, Map<String, List> bod

try {
if (isClientIdExistsAsParams(request, bodyParams)) {
if (canBypassClientCredentials(context.getClientId())) {
if (canBypassClientCredentials(context.getClientId(), request)) {
if (clientId != null) {
context.setClientId(clientId);
}
Expand Down Expand Up @@ -172,15 +178,65 @@ public String getClientId(HttpServletRequest request, Map<String, List> bodyPara
/**
* Checks if the client can bypass credentials.
*
* @param clientId Client ID
* @return True is the client can bypass credentials, False otherwise.
* @throws IdentityOAuth2Exception OAuth2 exception.
* @throws InvalidOAuthClientException Invalid OAuth2 client exception.
* @param clientId Client ID of the application.
* @param request HttpServletRequest which is the incoming request.
* @return True if the client can bypass credentials, False otherwise.
* @throws IdentityOAuth2Exception Error while retrieving the OAuth application's information by client ID.
* @throws InvalidOAuthClientException Error due to an invalid or non-existent client ID (consumer key).
*/
private boolean canBypassClientCredentials(String clientId) throws IdentityOAuth2Exception,
InvalidOAuthClientException {
private boolean canBypassClientCredentials(String clientId, HttpServletRequest request)
throws IdentityOAuth2Exception, InvalidOAuthClientException {

String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();

// Inherit the main app's isPublicClient property for the shared app only in the API-based authentication flow.
if (OAuth2Util.isApiBasedAuthenticationFlow(request)) {
String organizationID = PrivilegedCarbonContext.getThreadLocalCarbonContext().getOrganizationId();
if (StringUtils.isNotEmpty(organizationID)) {
return canBypassClientCredentialsForSharedApp(clientId, tenantDomain);
}
}
return OAuth2Util.getAppInformationByClientId(clientId, tenantDomain).isBypassClientCredentials();
}

return OAuth2Util.getAppInformationByClientId(clientId).isBypassClientCredentials();
/**
* Resolves the bypassClientCredentials property for the shared application for API Based Authentication.
*
* @param clientId Client ID of the shared application.
* @param tenantDomain Tenant domain of the shared application.
* @return True if the main application bypasses client credentials; Else, returns the shared application's value.
* @throws IdentityOAuth2Exception Error while retrieving the OAuth application's information by client ID.
* @throws InvalidOAuthClientException Error due to an invalid or non-existent client ID (consumer key).
*/
private boolean canBypassClientCredentialsForSharedApp(String clientId, String tenantDomain)
throws IdentityOAuth2Exception, InvalidOAuthClientException {

OAuthAppDO oAuthAppDO = OAuth2Util.getAppInformationByClientId(clientId, tenantDomain);
try {
String sharedApplicationID = OAuth2ServiceComponentHolder.getApplicationMgtService()
.getApplicationResourceIDByInboundKey(clientId,
OAuthConstants.Scope.OAUTH2, tenantDomain);
String mainApplicationID = OAuth2ServiceComponentHolder.getApplicationMgtService()
.getMainAppId(sharedApplicationID);
int mainAppTenantId = OAuth2ServiceComponentHolder.getApplicationMgtService()
.getTenantIdByApp(mainApplicationID);

OAuthConsumerAppDTO mainOAuthAppDO = OAuth2ServiceComponentHolder.getInstance()
.getOAuthAdminService()
.getOAuthApplicationDataByAppName(oAuthAppDO.getApplicationName(), mainAppTenantId);

if (mainOAuthAppDO != null && mainOAuthAppDO.isBypassClientCredentials()) {
return true;
}
} catch (IdentityApplicationManagementException e) {
log.error("Failed to retrieve main application details for the shared application with client ID: "
+ clientId + " to resolve the isBypassClientCredentials property.", e);
} catch (IdentityOAuthAdminException e) {
log.error("Failed to retrieve OAuth app data for the main application " +
"associated with the shared application with client ID: " + clientId +
" to resolve the isBypassClientCredentials property.", e);
}
return oAuthAppDO.isBypassClientCredentials();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2017-2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand Down Expand Up @@ -104,10 +104,10 @@
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.testng.Assert.assertThrows;
import static org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_ID;
import static org.wso2.carbon.identity.oauth.common.OAuthConstants.ENABLE_CLAIMS_SEPARATION_FOR_ACCESS_TOKEN;
import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDC_DIALECT;
import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_ID;

public class OAuthAdminServiceImplTest {

Expand Down Expand Up @@ -485,12 +485,13 @@ public void testGetOAuthApplicationDataException(String exception) throws Except
public void testGetOAuthApplicationDataByAppName() throws Exception {

String appName = "some-app-name";
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(SUPER_TENANT_ID);

// Create oauth application data.
OAuthAppDO app = buildDummyOAuthAppDO("some-user-name");
try (MockedConstruction<OAuthAppDAO> mockedConstruction = Mockito.mockConstruction(OAuthAppDAO.class,
(mock, context) -> {
when(mock.getAppInformationByAppName(appName)).thenReturn(app);
when(mock.getAppInformationByAppName(appName, SUPER_TENANT_ID)).thenReturn(app);
})) {

OAuthAdminServiceImpl oAuthAdminServiceImpl = new OAuthAdminServiceImpl();
Expand All @@ -504,15 +505,18 @@ public void testGetOAuthApplicationDataByAppName() throws Exception {
public void testGetOAuthApplicationDataByAppNameException(String exception) throws Exception {

String appName = "some-app-name";
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(SUPER_TENANT_ID);

try (MockedConstruction<OAuthAppDAO> mockedConstruction = Mockito.mockConstruction(OAuthAppDAO.class,
(mock, context) -> {
switch (exception) {
case "InvalidOAuthClientException":
when(mock.getAppInformationByAppName(appName)).thenThrow(InvalidOAuthClientException.class);
when(mock.getAppInformationByAppName(appName, SUPER_TENANT_ID))
.thenThrow(InvalidOAuthClientException.class);
break;
case "IdentityOAuth2Exception":
when(mock.getAppInformationByAppName(appName)).thenThrow(IdentityOAuth2Exception.class);
when(mock.getAppInformationByAppName(appName, SUPER_TENANT_ID))
.thenThrow(IdentityOAuth2Exception.class);
}
})) {

Expand Down
Loading

0 comments on commit b069af4

Please sign in to comment.