/*
* Copyright (c) 2015, 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.
* 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.registry.rest.api.handler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.configuration.security.AuthorizationPolicy;
import org.apache.cxf.jaxrs.ext.RequestHandler;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.message.Message;
import org.apache.cxf.transport.http.auth.HttpAuthHeader;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.registry.core.config.RegistryContext;
import org.wso2.carbon.registry.rest.api.exception.RestApiBasicAuthenticationException;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.user.core.tenant.TenantManager;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import javax.ws.rs.core.Response;
public class RestApiBasicAuthenticationHandler implements RequestHandler {
protected Log log = LogFactory.getLog(RestApiBasicAuthenticationHandler.class);
/**
* Implementation of RequestHandler.handleRequest method.
* This method retrieves userName and password from Basic auth header,
* and tries to authenticate against carbon user store
*
* Upon successful authentication allows process to proceed to retrieve requested REST resource
* Upon invalid credentials returns a HTTP 401 UNAUTHORIZED response to client
* Upon receiving a userStoreExceptions or IdentityException returns HTTP 500 internal server error to client
*
* @param message
* @param classResourceInfo
* @return Response
*/
public Response handleRequest(Message message, ClassResourceInfo classResourceInfo) {
if (log.isDebugEnabled()) {
log.debug("Registry REST API Basic authentication handler execution started");
}
AuthorizationPolicy policy = message.get(AuthorizationPolicy.class);
if (policy != null && HttpAuthHeader.AUTH_TYPE_BASIC.equals(policy.getAuthorizationType())) {
try {
if (authenticate(policy.getUserName(), policy.getPassword())) {
return null;
}
} catch (RestApiBasicAuthenticationException e) {
/* Upon an occurrence of exception log the caught exception
* and return a HTTP response with 500 server error response */
log.error("Could not authenticate user : " + policy.getUserName() + "against carbon userStore", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
return Response.status(Response.Status.UNAUTHORIZED).header("WWW-Authenticate", HttpAuthHeader.AUTH_TYPE_BASIC).build();
}
return null;
}
/**
* Checks whether a given userName:password combination authenticates correctly against carbon userStore
* Upon successful authentication returns true, false otherwise
*
* @param userName
* @param password
* @return
* @throws RestApiBasicAuthenticationException wraps and throws exceptions occur when trying to authenticate
* the user
*/
private boolean authenticate(String userName, String password) throws RestApiBasicAuthenticationException {
String tenantDomain = MultitenantUtils.getTenantDomain(userName);
String tenantAwareUserName = MultitenantUtils.getTenantAwareUsername(userName);
String userNameWithTenantDomain = tenantAwareUserName + "@" + tenantDomain;
RealmService realmService = RegistryContext.getBaseInstance().getRealmService();
TenantManager mgr = realmService.getTenantManager();
int tenantId = 0;
try {
tenantId = mgr.getTenantId(tenantDomain);
} catch (UserStoreException e) {
throw new RestApiBasicAuthenticationException(
"Identity exception thrown while getting tenant ID for user : " + userNameWithTenantDomain, e);
}
// tenantId == -1, means an invalid tenant.
if(tenantId == -1){
if (log.isDebugEnabled()) {
log.debug("Basic authentication request with an invalid tenant : " + userNameWithTenantDomain);
}
return false;
}
UserStoreManager userStoreManager = null;
boolean authStatus = false;
try {
userStoreManager = realmService.getTenantUserRealm(tenantId).getUserStoreManager();
authStatus = userStoreManager.authenticate(tenantAwareUserName, password);
} catch (UserStoreException e) {
throw new RestApiBasicAuthenticationException(
"User store exception thrown while authenticating user : " + userNameWithTenantDomain, e);
}
if(log.isDebugEnabled()){
log.debug("Basic authentication request completed. " +
"Username : " + userNameWithTenantDomain +
", Authentication State : " + authStatus);
}
if (authStatus){
/* Upon successful authentication existing thread local carbon context
* is updated to mimic the authenticated user */
PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
carbonContext.setUsername(userName);
carbonContext.setTenantId(tenantId);
carbonContext.setTenantDomain(tenantDomain);
}
return authStatus;
}
}