/*
* Copyright (c) 2010, 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
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.identity.scim.provider.auth;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.message.Message;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.application.common.model.ProvisioningServiceProviderType;
import org.wso2.carbon.identity.application.common.model.ThreadLocalProvisioningServiceProvider;
import org.wso2.carbon.identity.application.common.util.IdentityApplicationManagementUtil;
import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService;
import org.wso2.carbon.identity.oauth2.dto.OAuth2ClientApplicationDTO;
import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationRequestDTO;
import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationResponseDTO;
import org.wso2.carbon.identity.scim.provider.util.SCIMProviderConstants;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import org.wso2.charon.core.schema.SCIMConstants;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class OAuthHandler implements SCIMAuthenticationHandler {
private static Log log = LogFactory.getLog(BasicAuthHandler.class);
/* constants specific to this authenticator */
private final String BEARER_AUTH_HEADER = "Bearer";
private final String LOCAL_PREFIX = "local";
private final int DEFAULT_PRIORITY = 10;
private final String LOCAL_AUTH_SERVER = "local://services";
/* properties map to be initialized */
private Map<String, String> properties;
/* properties specific to this authenticator */
private String remoteServiceURL;
private int priority;
private String userName;
private String password;
// Ideally this should be configurable. For the moment, hard code the priority.
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public void setDefaultPriority() {
this.priority = DEFAULT_PRIORITY;
}
public void setDefaultAuthzServer() {
this.remoteServiceURL = LOCAL_AUTH_SERVER;
}
public boolean canHandle(Message message, ClassResourceInfo classResourceInfo) {
// check the "Authorization" header and if "Bearer" is there, can be handled.
// get the map of protocol headers
Map protocolHeaders = (TreeMap) message.get(Message.PROTOCOL_HEADERS);
// get the value for Authorization Header
List authzHeaders = (ArrayList) protocolHeaders
.get(SCIMConstants.AUTHORIZATION_HEADER);
if (authzHeaders != null) {
// get the authorization header value, if provided
String authzHeader = (String) authzHeaders.get(0);
if (authzHeader != null && authzHeader.contains(BEARER_AUTH_HEADER)) {
return true;
}
}
return false;
}
public boolean isAuthenticated(Message message, ClassResourceInfo classResourceInfo) {
// get the map of protocol headers
Map protocolHeaders = (TreeMap) message.get(Message.PROTOCOL_HEADERS);
// get the value for Authorization Header
List authzHeaders = (ArrayList) protocolHeaders
.get(SCIMConstants.AUTHORIZATION_HEADER);
if (authzHeaders != null) {
// get the authorization header value, if provided
String authzHeader = (String) authzHeaders.get(0);
// extract access token
String accessToken = authzHeader.trim().substring(7).trim();
// validate access token
try {
OAuth2ClientApplicationDTO validationApp = this.validateAccessToken(accessToken);
OAuth2TokenValidationResponseDTO validationResponse = null;
if (validationApp != null) {
validationResponse = validationApp.getAccessTokenValidationResponse();
}
if (validationResponse != null && validationResponse.isValid()) {
String userName = validationResponse.getAuthorizedUser();
authzHeaders.set(0, userName);
// setup thread local variable to be consumed by the provisioning framework.
RealmService realmService = (RealmService) PrivilegedCarbonContext
.getThreadLocalCarbonContext().getOSGiService(RealmService.class);
ThreadLocalProvisioningServiceProvider serviceProvider = new ThreadLocalProvisioningServiceProvider();
serviceProvider.setServiceProviderName(validationApp.getConsumerKey());
serviceProvider
.setServiceProviderType(ProvisioningServiceProviderType.OAUTH);
serviceProvider.setClaimDialect(SCIMProviderConstants.DEFAULT_SCIM_DIALECT);
serviceProvider.setTenantDomain(MultitenantUtils.getTenantDomain(userName));
IdentityApplicationManagementUtil
.setThreadLocalProvisioningServiceProvider(serviceProvider);
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
String tenantDomain = MultitenantUtils.getTenantDomain(userName);
carbonContext.setUsername(MultitenantUtils.getTenantAwareUsername(userName));
carbonContext.setTenantId(realmService.getTenantManager().getTenantId(tenantDomain));
carbonContext.setTenantDomain(tenantDomain);
return true;
}
} catch (Exception e) {
String error = "Error in validating OAuth access token.";
log.error(error, e);
}
}
return false;
}
/**
* To set the properties specific to each authenticator
*
* @param authenticatorProperties
*/
public void setProperties(Map<String, String> authenticatorProperties) {
this.properties = authenticatorProperties;
String priorityString = properties.get(SCIMProviderConstants.PROPERTY_NAME_PRIORITY);
if (priorityString != null) {
priority = Integer.parseInt(priorityString);
} else {
priority = DEFAULT_PRIORITY;
}
String remoteURLString = properties.get(SCIMProviderConstants.PROPERTY_NAME_AUTH_SERVER);
if (remoteURLString != null) {
remoteServiceURL = remoteURLString;
} else {
remoteServiceURL = LOCAL_AUTH_SERVER;
}
userName = properties.get(SCIMProviderConstants.PROPERTY_NAME_USERNAME);
password = properties.get(SCIMProviderConstants.PROPERTY_NAME_PASSWORD);
}
private String getOAuthAuthzServerURL() {
if (remoteServiceURL != null && !remoteServiceURL.endsWith("/")) {
remoteServiceURL += "/";
}
return remoteServiceURL;
}
private OAuth2ClientApplicationDTO validateAccessToken(String accessTokenIdentifier)
throws Exception {
// if it is specified to use local authz server (i.e: local://services)
if (remoteServiceURL.startsWith(LOCAL_PREFIX)) {
OAuth2TokenValidationRequestDTO oauthValidationRequest = new OAuth2TokenValidationRequestDTO();
OAuth2TokenValidationRequestDTO.OAuth2AccessToken accessToken = oauthValidationRequest.new OAuth2AccessToken();
accessToken.setTokenType(OAuthServiceClient.BEARER_TOKEN_TYPE);
accessToken.setIdentifier(accessTokenIdentifier);
oauthValidationRequest.setAccessToken(accessToken);
OAuth2TokenValidationService oauthValidationService = new OAuth2TokenValidationService();
OAuth2ClientApplicationDTO oauthValidationResponse = oauthValidationService
.findOAuthConsumerIfTokenIsValid(oauthValidationRequest);
return oauthValidationResponse;
}
// else do a web service call to the remote authz server
try {
ConfigurationContext configContext = ConfigurationContextFactory
.createConfigurationContextFromFileSystem(null, null);
OAuthServiceClient oauthClient = new OAuthServiceClient(getOAuthAuthzServerURL(),
userName, password, configContext);
org.wso2.carbon.identity.oauth2.stub.dto.OAuth2ClientApplicationDTO validationResponse;
validationResponse = oauthClient.findOAuthConsumerIfTokenIsValid(accessTokenIdentifier);
OAuth2ClientApplicationDTO appDTO = new OAuth2ClientApplicationDTO();
appDTO.setConsumerKey(validationResponse.getConsumerKey());
OAuth2TokenValidationResponseDTO validationDto = new OAuth2TokenValidationResponseDTO();
validationDto.setAuthorizedUser(validationResponse.getAccessTokenValidationResponse()
.getAuthorizedUser());
validationDto
.setValid(validationResponse.getAccessTokenValidationResponse().getValid());
appDTO.setAccessTokenValidationResponse(validationDto);
return appDTO;
} catch (AxisFault axisFault) {
throw axisFault;
} catch (Exception exception) {
throw exception;
}
}
}