/* * Copyright (c) 2014, 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.application.authenticator.basicauth; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.application.authentication.framework.AbstractApplicationAuthenticator; import org.wso2.carbon.identity.application.authentication.framework.AuthenticatorFlowStatus; import org.wso2.carbon.identity.application.authentication.framework.LocalApplicationAuthenticator; import org.wso2.carbon.identity.application.authentication.framework.config.ConfigurationFacade; import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; import org.wso2.carbon.identity.application.authentication.framework.exception.AuthenticationFailedException; import org.wso2.carbon.identity.application.authentication.framework.exception.InvalidCredentialsException; import org.wso2.carbon.identity.application.authentication.framework.exception.LogoutFailedException; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.authenticator.basicauth.internal.BasicAuthenticatorServiceComponent; import org.wso2.carbon.identity.base.IdentityRuntimeException; import org.wso2.carbon.identity.core.model.IdentityErrorMsgContext; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.user.api.UserRealm; import org.wso2.carbon.user.core.UserCoreConstants; import org.wso2.carbon.user.core.UserStoreException; import org.wso2.carbon.user.core.UserStoreManager; import org.wso2.carbon.user.core.util.UserCoreUtil; import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; /** * Username Password based Authenticator */ public class BasicAuthenticator extends AbstractApplicationAuthenticator implements LocalApplicationAuthenticator { private static final long serialVersionUID = 1819664539416029785L; private static final Log log = LogFactory.getLog(BasicAuthenticator.class); @Override public boolean canHandle(HttpServletRequest request) { String userName = request.getParameter(BasicAuthenticatorConstants.USER_NAME); String password = request.getParameter(BasicAuthenticatorConstants.PASSWORD); if (userName != null && password != null) { return true; } return false; } @Override public AuthenticatorFlowStatus process(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context) throws AuthenticationFailedException, LogoutFailedException { if (context.isLogoutRequest()) { return AuthenticatorFlowStatus.SUCCESS_COMPLETED; } else { return super.process(request, response, context); } } @Override protected void initiateAuthenticationRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context) throws AuthenticationFailedException { Map<String, String> parameterMap = getAuthenticatorConfig().getParameterMap(); String showAuthFailureReason = null; if (parameterMap != null) { showAuthFailureReason = parameterMap.get("showAuthFailureReason"); if (log.isDebugEnabled()) { log.debug("showAuthFailureReason has been set as : " + showAuthFailureReason); } } String loginPage = ConfigurationFacade.getInstance().getAuthenticationEndpointURL(); String retryPage = ConfigurationFacade.getInstance().getAuthenticationEndpointRetryURL(); String queryParams = context.getContextIdIncludedQueryParams(); try { String retryParam = ""; if (context.isRetrying()) { retryParam = "&authFailure=true&authFailureMsg=login.fail.message"; } if (context.getProperty("UserTenantDomainMismatch") != null && (Boolean)context.getProperty("UserTenantDomainMismatch")) { retryParam = "&authFailure=true&authFailureMsg=user.tenant.domain.mismatch.message"; context.setProperty("UserTenantDomainMismatch", false); } IdentityErrorMsgContext errorContext = IdentityUtil.getIdentityErrorMsg(); IdentityUtil.clearIdentityErrorMsg(); if (showAuthFailureReason != null && "true".equals(showAuthFailureReason)) { if (errorContext != null) { if (log.isDebugEnabled()) { log.debug("Identity error message context is not null"); } String errorCode = errorContext.getErrorCode(); int remainingAttempts = errorContext.getMaximumLoginAttempts() - errorContext.getFailedLoginAttempts(); if (log.isDebugEnabled()) { log.debug("errorCode : " + errorCode); log.debug("username : " + request.getParameter(BasicAuthenticatorConstants.USER_NAME)); log.debug("remainingAttempts : " + remainingAttempts); } if (errorCode.equals(UserCoreConstants.ErrorCode.INVALID_CREDENTIAL)) { retryParam = retryParam + BasicAuthenticatorConstants.ERROR_CODE + errorCode + BasicAuthenticatorConstants.FAILED_USERNAME + URLEncoder.encode(request.getParameter(BasicAuthenticatorConstants.USER_NAME), BasicAuthenticatorConstants.UTF_8) + "&remainingAttempts=" + remainingAttempts; response.sendRedirect(response.encodeRedirectURL(loginPage + ("?" + queryParams)) + BasicAuthenticatorConstants.AUTHENTICATORS + getName() + ":" + BasicAuthenticatorConstants.LOCAL + retryParam); } else if (errorCode.equals(UserCoreConstants.ErrorCode.USER_IS_LOCKED)) { String redirectURL = retryPage; if (remainingAttempts == 0) { redirectURL = response.encodeRedirectURL(redirectURL + ("?" + queryParams)) + BasicAuthenticatorConstants.ERROR_CODE + errorCode + BasicAuthenticatorConstants.FAILED_USERNAME + URLEncoder.encode(request.getParameter(BasicAuthenticatorConstants.USER_NAME), BasicAuthenticatorConstants.UTF_8) + "&remainingAttempts=0"; } else { redirectURL = response.encodeRedirectURL(redirectURL + ("?" + queryParams)) + BasicAuthenticatorConstants.ERROR_CODE + errorCode + BasicAuthenticatorConstants.FAILED_USERNAME + URLEncoder.encode(request.getParameter(BasicAuthenticatorConstants.USER_NAME), BasicAuthenticatorConstants.UTF_8); } response.sendRedirect(redirectURL); } else if (errorCode.equals(UserCoreConstants.ErrorCode.USER_DOES_NOT_EXIST)) { retryParam = retryParam + BasicAuthenticatorConstants.ERROR_CODE + errorCode + BasicAuthenticatorConstants.FAILED_USERNAME + URLEncoder.encode(request.getParameter(BasicAuthenticatorConstants.USER_NAME), BasicAuthenticatorConstants.UTF_8); response.sendRedirect(response.encodeRedirectURL(loginPage + ("?" + queryParams)) + BasicAuthenticatorConstants.AUTHENTICATORS + getName() + ":" + BasicAuthenticatorConstants.LOCAL + retryParam); } } else { response.sendRedirect(response.encodeRedirectURL(loginPage + ("?" + queryParams)) + BasicAuthenticatorConstants.AUTHENTICATORS + getName() + ":" + BasicAuthenticatorConstants.LOCAL + retryParam); } } else { String errorCode = errorContext != null ? errorContext.getErrorCode() : null; if (errorCode != null && errorCode.equals(UserCoreConstants.ErrorCode.USER_IS_LOCKED)) { String redirectURL = retryPage; redirectURL = response.encodeRedirectURL(redirectURL + ("?" + queryParams)) + BasicAuthenticatorConstants.FAILED_USERNAME + URLEncoder.encode(request.getParameter(BasicAuthenticatorConstants.USER_NAME), BasicAuthenticatorConstants.UTF_8); response.sendRedirect(redirectURL); } else { response.sendRedirect(response.encodeRedirectURL(loginPage + ("?" + queryParams)) + BasicAuthenticatorConstants.AUTHENTICATORS + getName() + ":" + BasicAuthenticatorConstants.LOCAL + retryParam); } } } catch (IOException e) { throw new AuthenticationFailedException(e.getMessage(), e); } } @Override protected void processAuthenticationResponse(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context) throws AuthenticationFailedException { String username = request.getParameter(BasicAuthenticatorConstants.USER_NAME); String password = request.getParameter(BasicAuthenticatorConstants.PASSWORD); boolean isAuthenticated; UserStoreManager userStoreManager; // Check the authentication try { int tenantId = IdentityTenantUtil.getTenantIdOfUser(username); UserRealm userRealm = BasicAuthenticatorServiceComponent.getRealmService().getTenantUserRealm(tenantId); if (userRealm != null) { userStoreManager = (UserStoreManager) userRealm.getUserStoreManager(); isAuthenticated = userStoreManager.authenticate(MultitenantUtils.getTenantAwareUsername(username), password); } else { throw new AuthenticationFailedException("Cannot find the user realm for the given tenant: " + tenantId); } } catch (IdentityRuntimeException e) { if(log.isDebugEnabled()){ log.debug("BasicAuthentication failed while trying to get the tenant ID of the user " + username, e); } throw new AuthenticationFailedException(e.getMessage(), e); } catch (org.wso2.carbon.user.api.UserStoreException e) { if(log.isDebugEnabled()){ log.debug("BasicAuthentication failed while trying to authenticate", e); } throw new AuthenticationFailedException(e.getMessage(), e); } if (!isAuthenticated) { if (log.isDebugEnabled()) { log.debug("User authentication failed due to invalid credentials"); } throw new InvalidCredentialsException("User authentication failed due to invalid credentials"); } Map<String, Object> authProperties = context.getProperties(); String tenantDomain = MultitenantUtils.getTenantDomain(username); if (authProperties == null) { authProperties = new HashMap<String, Object>(); context.setProperties(authProperties); } //TODO: user tenant domain has to be an attribute in the AuthenticationContext authProperties.put("user-tenant-domain", tenantDomain); username = FrameworkUtils.prependUserStoreDomainToName(username); if (getAuthenticatorConfig().getParameterMap() != null) { String userNameUri = getAuthenticatorConfig().getParameterMap().get("UserNameAttributeClaimUri"); if (userNameUri != null && userNameUri.trim().length() > 0) { boolean multipleAttributeEnable; String domain = UserCoreUtil.getDomainFromThreadLocal(); if (domain != null && domain.trim().length() > 0) { multipleAttributeEnable = Boolean.parseBoolean(userStoreManager.getSecondaryUserStoreManager(domain). getRealmConfiguration().getUserStoreProperty("MultipleAttributeEnable")); } else { multipleAttributeEnable = Boolean.parseBoolean(userStoreManager. getRealmConfiguration().getUserStoreProperty("MultipleAttributeEnable")); } if (multipleAttributeEnable) { try { if (log.isDebugEnabled()) { log.debug("Searching for UserNameAttribute value for user " + username + " for claim uri : " + userNameUri); } String usernameValue = userStoreManager. getUserClaimValue(MultitenantUtils.getTenantAwareUsername(username), userNameUri, null); if (usernameValue != null && usernameValue.trim().length() > 0) { tenantDomain = MultitenantUtils.getTenantDomain(username); usernameValue = FrameworkUtils.prependUserStoreDomainToName(usernameValue); username = usernameValue + "@" + tenantDomain; if (log.isDebugEnabled()) { log.debug("UserNameAttribute is found for user. Value is : " + username); } } } catch (UserStoreException e) { //ignore but log in debug if(log.isDebugEnabled()) { log.debug("Error while retrieving UserNameAttribute for user : " + username, e); } } } else { if (log.isDebugEnabled()) { log.debug("MultipleAttribute is not enabled for user store domain : " + domain + " " + "Therefore UserNameAttribute is not retrieved"); } } } } context.setSubject(AuthenticatedUser.createLocalAuthenticatedUserFromSubjectIdentifier(username)); String rememberMe = request.getParameter("chkRemember"); if (rememberMe != null && "on".equals(rememberMe)) { context.setRememberMe(true); } } @Override protected boolean retryAuthenticationEnabled() { return true; } @Override public String getContextIdentifier(HttpServletRequest request) { return request.getParameter("sessionDataKey"); } @Override public String getFriendlyName() { return BasicAuthenticatorConstants.AUTHENTICATOR_FRIENDLY_NAME; } @Override public String getName() { return BasicAuthenticatorConstants.AUTHENTICATOR_NAME; } }