Skip to content

Commit

Permalink
Call app-mgt component to handle inbound details (#543)
Browse files Browse the repository at this point in the history
* Call app-mgt component to handle inbound details
* Fix NPE
* bump version
* Add license headers
* Address comment
---------
Co-authored-by: vivekvinushanth <[email protected]>
  • Loading branch information
sahandilshan authored Mar 12, 2024
1 parent b3c210a commit f1974d0
Show file tree
Hide file tree
Showing 13 changed files with 310 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@
<artifactId>org.wso2.carbon.identity.oauth</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.inbound.auth.oauth2</groupId>
<artifactId>org.wso2.carbon.identity.oauth.common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.inbound.auth.saml2</groupId>
<artifactId>org.wso2.carbon.identity.sso.saml</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.ServiceProviderToApiModel;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.UpdateServiceProvider;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.InboundAuthConfigToApiModel;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.PassiveSTSInboundFunctions;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.WSTrustInboundFunctions;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.custom.CustomInboundFunctions;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.oauth2.OAuthInboundFunctions;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.passive.sts.PassiveSTSInboundFunctions;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.saml.SAMLInboundFunctions;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.provisioning.BuildProvisioningConfiguration;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.provisioning.UpdateProvisioningConfiguration;
Expand Down Expand Up @@ -107,6 +107,8 @@
import org.wso2.carbon.identity.application.mgt.ApplicationConstants;
import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.application.mgt.AuthorizedAPIManagementService;
import org.wso2.carbon.identity.application.mgt.inbound.dto.ApplicationDTO;
import org.wso2.carbon.identity.application.mgt.inbound.dto.InboundProtocolConfigurationDTO;
import org.wso2.carbon.identity.base.IdentityException;
import org.wso2.carbon.identity.configuration.mgt.core.model.ResourceSearchBean;
import org.wso2.carbon.identity.configuration.mgt.core.search.ComplexCondition;
Expand Down Expand Up @@ -151,15 +153,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
Expand All @@ -183,7 +183,6 @@
import static org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.InboundFunctions.getInboundAuthKey;
import static org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.InboundFunctions.getInboundAuthenticationRequestConfig;
import static org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.InboundFunctions.rollbackInbound;
import static org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.InboundFunctions.rollbackInbounds;
import static org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.InboundFunctions.updateOrInsertInbound;
import static org.wso2.carbon.identity.api.server.common.Constants.ERROR_CODE_RESOURCE_LIMIT_REACHED;
import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.Application.CONSOLE_APP;
Expand Down Expand Up @@ -764,7 +763,8 @@ public String createApplication(ApplicationModel applicationModel, String templa

/*
* CORS adding step should be moved to the service layer and the validation also should happen there.
* But for now we are handling the validation here.
* But for now we are handling the validation here. (This should move when the CORS management is
* moved to the service layer).
*/
if (applicationModel.getInboundProtocolConfiguration() != null &&
applicationModel.getInboundProtocolConfiguration().getOidc() != null) {
Expand Down Expand Up @@ -797,14 +797,14 @@ public String createApplication(ApplicationModel applicationModel, String templa
String tenantDomain = ContextLoader.getTenantDomainFromContext();

String applicationId = null;
ServiceProvider application = new ApiModelToServiceProvider().apply(applicationModel);
try {
applicationId = getApplicationManagementService().createApplication(application, tenantDomain, username);

ApplicationDTO applicationDTO = new ApiModelToServiceProvider().apply(applicationModel);
applicationId = getApplicationManagementService().createApplication(applicationDTO, tenantDomain, username);

// Update owner for B2B Self Service applications.
if (application.isB2BSelfServiceApp()) {
if (applicationDTO.getServiceProvider().isB2BSelfServiceApp()) {
String systemUserID = org.wso2.carbon.identity.organization.management.service.util.Utils
.getB2BSelfServiceSystemUser(tenantDomain);
.getB2BSelfServiceSystemUser(tenantDomain);
if (StringUtils.isNotEmpty(systemUserID)) {
ApplicationOwner systemOwner = new ApplicationOwner();
systemOwner.id(systemUserID);
Expand All @@ -819,10 +819,6 @@ public String createApplication(ApplicationModel applicationModel, String templa
}
return applicationId;
} catch (IdentityApplicationManagementException e) {
if (log.isDebugEnabled()) {
log.debug("Error while creating application. Rolling back possibly created inbound config data.", e);
}
rollbackInbounds(getConfiguredInbounds(application));
throw handleIdentityApplicationManagementException(e, "Error creating application.");
} catch (CORSManagementServiceException e) {
if (log.isDebugEnabled()) {
Expand All @@ -841,14 +837,10 @@ public String createApplication(ApplicationModel applicationModel, String templa
* For more information read https://github.com/wso2/product-is/issues/12579. This is to overcome the
* above issue.
*/
if (log.isDebugEnabled()) {
log.debug("Server encountered unexpected error. Rolling back created application data.", e);
}
if (applicationId != null) {
deleteApplication(applicationId);
} else {
rollbackInbounds(getConfiguredInbounds(application));
}
log.error(ERROR_PROCESSING_REQUEST.getDescription(), e);
throw Utils.buildServerError(ERROR_PROCESSING_REQUEST.getCode(), ERROR_PROCESSING_REQUEST.getMessage(),
ERROR_PROCESSING_REQUEST.getDescription());
}
Expand Down Expand Up @@ -1056,12 +1048,12 @@ public void putInboundOAuthConfiguration(String applicationId, OpenIDConnectConf
* But for now we are handling the validation here.
*/
validateCORSOrigins(oidcConfigModel.getAllowedOrigins());
putInbound(applicationId, oidcConfigModel, OAuthInboundFunctions::putOAuthInbound);
putApplicationInbound(applicationId, oidcConfigModel, OAuthInboundFunctions::getInboundProtocolConfig);
}

public void putInboundSAMLConfiguration(String applicationId, SAML2Configuration saml2Configuration) {

putInbound(applicationId, saml2Configuration, SAMLInboundFunctions::putSAMLInbound);
putApplicationInbound(applicationId, saml2Configuration, SAMLInboundFunctions::getInboundProtocolConfig);
}

public void putInboundPassiveSTSConfiguration(String applicationId,
Expand Down Expand Up @@ -1619,7 +1611,9 @@ private void deleteInbound(String applicationId, String inboundType) {
.toArray(InboundAuthenticationRequestConfig[]::new);

appToUpdate.getInboundAuthenticationConfig().setInboundAuthenticationRequestConfigs(filteredInbounds);
updateServiceProvider(applicationId, appToUpdate);
// We don't need to pass the inboundDTO information here since the updated inbound is already removed at
// this point and also updated in the appToUpdate object.
updateServiceProvider(applicationId, appToUpdate, null);
}

// Delete the associated CORS origins if the inboundType is oauth2.
Expand Down Expand Up @@ -1659,15 +1653,6 @@ private ServiceProvider getServiceProvider(String applicationId) {
return application;
}

private List<InboundAuthenticationRequestConfig> getConfiguredInbounds(ServiceProvider app) {

if (app.getInboundAuthenticationConfig() != null &&
app.getInboundAuthenticationConfig().getInboundAuthenticationRequestConfigs() != null) {
return Arrays.asList(app.getInboundAuthenticationConfig().getInboundAuthenticationRequestConfigs());
}
return Collections.emptyList();
}

private List<ApplicationListItem> getApplicationListItems(ApplicationBasicInfo[] allApplicationBasicInfo) {

return Arrays.stream(allApplicationBasicInfo)
Expand Down Expand Up @@ -1736,6 +1721,34 @@ private <I> void putInbound(String applicationId,
throw error;
}
}

/**
* Create or replace the provided inbound configuration.
*
* @param applicationId Resource id of the app.
* @param inboundApiModel Inbound API model to be created or replaced.
* @param getInboundDTO A function that takes the inbound API model and application as input and provides the
* InboundProtocolConfigurationDTO that matches with the protocol.
*/
private <I> void putApplicationInbound(String applicationId, I inboundApiModel, BiFunction<ServiceProvider, I,
InboundProtocolConfigurationDTO> getInboundDTO) {

// We need a cloned copy of the Service Provider so that we changes we do not make cache dirty.
ServiceProvider application = cloneApplication(applicationId);

// Update the service provider with the inbound configuration.
InboundProtocolConfigurationDTO inboundDTO = getInboundDTO.apply(application, inboundApiModel);
try {
// Call the app-mgt service and update the inbound auth configs and application details
updateServiceProvider(applicationId, application, inboundDTO);
} catch (APIError error) {
if (log.isDebugEnabled()) {
log.debug("Error while updating application: " + applicationId + ". The possible rollbacks will be " +
"handle from the framework level.");
}
throw error;
}
}

private void doRollback(String applicationId, InboundAuthenticationRequestConfig updatedInbound) {

Expand All @@ -1756,13 +1769,30 @@ private void doRollback(String applicationId, InboundAuthenticationRequestConfig
}

private void updateServiceProvider(String applicationId, ServiceProvider updatedApplication) {

try {
String tenantDomain = ContextLoader.getTenantDomainFromContext();
String username = ContextLoader.getUsernameFromContext();


// Inbound auth config details are already added to the service provider. Therefore we don't need to pass
// the inboundDTO information here.
getApplicationManagementService().updateApplicationByResourceId(
applicationId, updatedApplication, null, tenantDomain, username);
} catch (IdentityApplicationManagementException e) {
String msg = "Error updating application with id: " + applicationId;
throw handleIdentityApplicationManagementException(e, msg);
}
}

private void updateServiceProvider(String applicationId, ServiceProvider updatedApplication,
InboundProtocolConfigurationDTO inboundDTO) {

try {
String tenantDomain = ContextLoader.getTenantDomainFromContext();
String username = ContextLoader.getUsernameFromContext();

getApplicationManagementService().updateApplicationByResourceId(
applicationId, updatedApplication, tenantDomain, username);
applicationId, updatedApplication, inboundDTO, tenantDomain, username);
} catch (IdentityApplicationManagementException e) {
String msg = "Error updating application with id: " + applicationId;
throw handleIdentityApplicationManagementException(e, msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,26 @@

import org.wso2.carbon.identity.api.server.application.management.v1.AdvancedApplicationConfiguration;
import org.wso2.carbon.identity.api.server.application.management.v1.ApplicationModel;
import org.wso2.carbon.identity.api.server.application.management.v1.AssociatedRolesConfig;
import org.wso2.carbon.identity.api.server.application.management.v1.AuthenticationSequence;
import org.wso2.carbon.identity.api.server.application.management.v1.ClaimConfiguration;
import org.wso2.carbon.identity.api.server.application.management.v1.InboundProtocols;
import org.wso2.carbon.identity.api.server.application.management.v1.ProvisioningConfiguration;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.UpdateInboundProtocols;
import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.provisioning.UpdateProvisioningConfiguration;
import org.wso2.carbon.identity.application.common.IdentityApplicationManagementClientException;
import org.wso2.carbon.identity.application.common.model.ServiceProvider;

import java.util.function.Function;
import org.wso2.carbon.identity.application.mgt.inbound.dto.ApplicationDTO;
import org.wso2.carbon.identity.application.mgt.inbound.dto.InboundProtocolsDTO;

import static org.wso2.carbon.identity.api.server.application.management.v1.core.functions.Utils.setIfNotNull;

/**
* Converts the API model object into a ServiceProvider object.
*/
public class ApiModelToServiceProvider implements Function<ApplicationModel, ServiceProvider> {
public class ApiModelToServiceProvider implements ModelToDTO<ApplicationModel, ApplicationDTO> {

@Override
public ServiceProvider apply(ApplicationModel applicationModel) {
public ApplicationDTO apply(ApplicationModel applicationModel) throws IdentityApplicationManagementClientException {

ServiceProvider application = new ServiceProvider();

Expand All @@ -55,30 +55,36 @@ public ServiceProvider apply(ApplicationModel applicationModel) {
addClaimConfigurationToApplication(application, applicationModel.getClaimConfiguration());
addAuthenticationSequence(application, applicationModel.getAuthenticationSequence());
addProvisioningConfiguration(application, applicationModel.getProvisioningConfigurations());
addInboundAuthenticationProtocolsToApplication(application, applicationModel.getInboundProtocolConfiguration());
addAssociatedRolesConfigurations(application, applicationModel.getAssociatedRoles());
addLogoutReturnUrl(application, applicationModel.getLogoutReturnUrl());
return application;
}

private void addLogoutReturnUrl(ServiceProvider application, String logoutReturnUrl) {
ApplicationDTO.Builder applicationDTOBuilder = new ApplicationDTO.Builder();
applicationDTOBuilder.serviceProvider(application);

new UpdateLogoutReturnUrl().apply(application, logoutReturnUrl);
// Converting InboundProtocols to InboundProtocolsDTO and adding it to the ApplicationModel.
applicationDTOBuilder.inboundProtocolConfigurationDto(
createInboundProtocolConfiguration(application, applicationModel.getInboundProtocolConfiguration()));
// This is to add the inbound authentication protocols to the application that doesn't have inbound auth
// config handler.
addInboundAuthenticationProtocolsToApplication(application, applicationModel.getInboundProtocolConfiguration());
return applicationDTOBuilder.build();
}

private void addAssociatedRolesConfigurations(ServiceProvider application, AssociatedRolesConfig associatedRoles) {
private void addInboundAuthenticationProtocolsToApplication(ServiceProvider application,
InboundProtocols inboundProtocolsModel) {

if (associatedRoles != null) {
new UpdateAssociatedRoles().apply(application, associatedRoles);
if (inboundProtocolsModel != null) {
new UpdateInboundProtocols().apply(application, inboundProtocolsModel);
}
}

private void addInboundAuthenticationProtocolsToApplication(ServiceProvider application,
InboundProtocols inboundProtocolsModel) {
private InboundProtocolsDTO createInboundProtocolConfiguration(ServiceProvider serviceProvider,
InboundProtocols inboundProtocolsModel)
throws IdentityApplicationManagementClientException {


if (inboundProtocolsModel != null) {
new UpdateInboundProtocols().apply(application, inboundProtocolsModel);
return new InboundProtocolToDTO().apply(serviceProvider, inboundProtocolsModel);
}
return null;
}

private void addAuthenticationSequence(ServiceProvider application, AuthenticationSequence authSequenceApiModel) {
Expand Down
Loading

0 comments on commit f1974d0

Please sign in to comment.