/*
* 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.axiom.om.util.Base64;
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.ThreadLocalProvisioningServiceProvider;
import org.wso2.carbon.identity.application.common.util.IdentityApplicationManagementUtil;
import org.wso2.carbon.identity.provisioning.IdentityProvisioningConstants;
import org.wso2.carbon.identity.scim.provider.util.SCIMProviderConstants;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import org.wso2.charon.core.exceptions.InternalServerException;
import org.wso2.charon.core.exceptions.UnauthorizedException;
import org.wso2.charon.core.schema.SCIMConstants;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* This is the default BASIC-Auth authentication handler for SCIM REST Endpoints.
*/
public class BasicAuthHandler implements SCIMAuthenticationHandler {
private static Log log = LogFactory.getLog(BasicAuthHandler.class);
/* constants specific to this authenticator */
private final String BASIC_AUTH_HEADER = "Basic";
private final int DEFAULT_PRIORITY = 5;
/* property map */
private Map<String, String> properties;
/* properties specific to this authenticator */
private int priority;
public void setDefaultPriority() {
priority = DEFAULT_PRIORITY;
}
/**
* Ideally this should be configurable. For the moment, hard code the priority.
*
* @return
*/
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean canHandle(Message message, ClassResourceInfo classResourceInfo) {
// check the "Authorization" header and if "Basic" 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(BASIC_AUTH_HEADER)) {
return true;
}
}
return false;
}
public boolean isAuthenticated(Message message, ClassResourceInfo classResourceInfo) {
// extract authorization header and authenticate.
// 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);
// decode it and extract username and password
byte[] decodedAuthHeader = Base64.decode(authzHeader.split(" ")[1]);
String authHeader = new String(decodedAuthHeader);
String userName = authHeader.split(":")[0];
String password = authHeader.split(":")[1];
if (userName != null && password != null) {
String tenantDomain = MultitenantUtils.getTenantDomain(userName);
String tenantLessUserName = MultitenantUtils.getTenantAwareUsername(userName);
try {
// get super tenant context and get realm service which is an osgi service
RealmService realmService = (RealmService) PrivilegedCarbonContext
.getThreadLocalCarbonContext().getOSGiService(RealmService.class);
if (realmService != null) {
int tenantId = realmService.getTenantManager().getTenantId(tenantDomain);
if (tenantId == -1) {
log.error("Invalid tenant domain " + tenantDomain);
return false;
}
// get tenant's user realm
UserRealm userRealm = realmService.getTenantUserRealm(tenantId);
boolean authenticated = userRealm.getUserStoreManager().authenticate(
tenantLessUserName, password);
if (authenticated) {
// setup thread local variable to be consumed by the provisioning
// framework.
ThreadLocalProvisioningServiceProvider serviceProvider = new ThreadLocalProvisioningServiceProvider();
serviceProvider
.setServiceProviderName(IdentityProvisioningConstants.LOCAL_SP);
serviceProvider
.setClaimDialect(SCIMProviderConstants.DEFAULT_SCIM_DIALECT);
serviceProvider.setTenantDomain(MultitenantUtils.getTenantDomain(userName));
IdentityApplicationManagementUtil
.setThreadLocalProvisioningServiceProvider(serviceProvider);
// authentication success. set the username for authorization header and
// proceed the REST call
authzHeaders.set(0, userName);
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
carbonContext.setUsername(tenantLessUserName);
carbonContext.setTenantId(tenantId);
carbonContext.setTenantDomain(tenantDomain);
return true;
} else {
UnauthorizedException unauthorizedException = new UnauthorizedException(
"Authentication failed for the user: " + tenantLessUserName
+ "@" + tenantDomain);
log.error(unauthorizedException.getDescription());
return false;
}
} else {
log.error("Error in getting Realm Service for user: " + userName);
InternalServerException internalServerException = new InternalServerException(
"Internal server error while authenticating the user: "
+ tenantLessUserName + "@" + tenantDomain);
log.error(internalServerException.getDescription());
return false;
}
} catch (UserStoreException e) {
InternalServerException internalServerException = new InternalServerException(
"Internal server error while authenticating the user.");
log.error(internalServerException.getDescription(), e);
return false;
}
} else {
UnauthorizedException unauthorizedException = new UnauthorizedException(
"Authentication required for this resource. Username or password not provided.");
log.error(unauthorizedException.getDescription());
return false;
}
} else {
UnauthorizedException unauthorizedException = new UnauthorizedException(
"Authentication required for this resource. Authorization header not present in the request.");
log.error(unauthorizedException.getDescription());
return false;
}
}
/**
* To set the properties specific to each authenticator
*
* @param authenticatorProperties
*/
public void setProperties(Map<String, String> authenticatorProperties) {
// set the priority read from config
this.properties = authenticatorProperties;
String priorityString = properties.get(SCIMProviderConstants.PROPERTY_NAME_PRIORITY);
if (priorityString != null) {
priority = Integer.parseInt(properties
.get(SCIMProviderConstants.PROPERTY_NAME_PRIORITY));
} else {
priority = DEFAULT_PRIORITY;
}
}
}