/*
* 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.mgt.util;
import org.apache.axiom.om.util.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.base.IdentityException;
import org.wso2.carbon.identity.mgt.IdentityMgtConfig;
import org.wso2.carbon.identity.mgt.constants.IdentityMgtConstants;
import org.wso2.carbon.identity.mgt.dto.UserDTO;
import org.wso2.carbon.identity.mgt.internal.IdentityMgtServiceComponent;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.user.api.Tenant;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.user.core.UserCoreConstants;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.user.core.tenant.TenantManager;
import org.wso2.carbon.user.core.util.UserCoreUtil;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import java.io.ByteArrayInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
public class Utils {
private static final Log log = LogFactory.getLog(Utils.class);
private Utils() {
}
public static UserDTO processUserId(String userId) throws IdentityException {
if (userId == null || userId.trim().length() < 1) {
throw IdentityException.error("Can not proceed with out a user id");
}
UserDTO userDTO = new UserDTO(userId);
if (!IdentityMgtConfig.getInstance().isSaasEnabled()) {
validateTenant(userDTO);
}
userDTO.setTenantId(getTenantId(userDTO.getTenantDomain()));
return userDTO;
}
public static void validateTenant(UserDTO user) throws IdentityException {
if (user.getTenantDomain() != null && !user.getTenantDomain().isEmpty()) {
if (!user.getTenantDomain().equals(
PrivilegedCarbonContext.getThreadLocalCarbonContext()
.getTenantDomain())) {
throw IdentityException.error(
"Failed access to unauthorized tenant domain");
}
user.setTenantId(getTenantId(user.getTenantDomain()));
}
}
/**
* gets no of verified user challenges
*
* @param userDTO bean class that contains user and tenant Information
* @return no of verified challenges
* @throws IdentityException if fails
*/
public static int getVerifiedChallenges(UserDTO userDTO) throws IdentityException {
int noOfChallenges = 0;
try {
UserRegistry registry = IdentityMgtServiceComponent.getRegistryService().
getConfigSystemRegistry(MultitenantConstants.SUPER_TENANT_ID);
String identityKeyMgtPath = IdentityMgtConstants.IDENTITY_MANAGEMENT_CHALLENGES +
RegistryConstants.PATH_SEPARATOR + userDTO.getUserId() +
RegistryConstants.PATH_SEPARATOR + userDTO.getUserId();
Resource resource;
if (registry.resourceExists(identityKeyMgtPath)) {
resource = registry.get(identityKeyMgtPath);
String property = resource.getProperty(IdentityMgtConstants.VERIFIED_CHALLENGES);
if (property != null) {
return Integer.parseInt(property);
}
}
} catch (RegistryException e) {
log.error("Error while processing userKey", e);
}
return noOfChallenges;
}
/**
* gets the tenant id from the tenant domain
*
* @param domain - tenant domain name
* @return tenantId
* @throws IdentityException if fails or tenant doesn't exist
*/
public static int getTenantId(String domain) throws IdentityException {
int tenantId;
TenantManager tenantManager = IdentityMgtServiceComponent.getRealmService().getTenantManager();
if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(domain)) {
tenantId = MultitenantConstants.SUPER_TENANT_ID;
if (log.isDebugEnabled()) {
String msg = "Domain is not defined implicitly. So it is Super Tenant domain.";
log.debug(msg);
}
} else {
try {
tenantId = tenantManager.getTenantId(domain);
if (tenantId < 1 && tenantId != MultitenantConstants.SUPER_TENANT_ID) {
String msg = "This action can not be performed by the users in non-existing domains.";
log.error(msg);
throw IdentityException.error(msg);
}
} catch (org.wso2.carbon.user.api.UserStoreException e) {
String msg = "Error in retrieving tenant id of tenant domain: " + domain + ".";
log.error(msg, e);
throw IdentityException.error(msg, e);
}
}
return tenantId;
}
/**
* Get the claims from the user store manager
*
* @param userName user name
* @param tenantId tenantId
* @param claim claim name
* @return claim value
* @throws IdentityException if fails
*/
public static String getClaimFromUserStoreManager(String userName, int tenantId, String claim)
throws IdentityException {
org.wso2.carbon.user.core.UserStoreManager userStoreManager = null;
RealmService realmService = IdentityMgtServiceComponent.getRealmService();
String claimValue = "";
try {
if (realmService.getTenantUserRealm(tenantId) != null) {
userStoreManager = (org.wso2.carbon.user.core.UserStoreManager) realmService.getTenantUserRealm(tenantId).
getUserStoreManager();
}
} catch (Exception e) {
String msg = "Error retrieving the user store manager for tenant id : " + tenantId;
log.error(msg, e);
throw IdentityException.error(msg, e);
}
try {
if (userStoreManager != null) {
Map<String, String> claimsMap = userStoreManager
.getUserClaimValues(userName, new String[]{claim}, UserCoreConstants.DEFAULT_PROFILE);
if (claimsMap != null && !claimsMap.isEmpty()) {
claimValue = claimsMap.get(claim);
}
}
return claimValue;
} catch (Exception e) {
String msg = "Unable to retrieve the claim for user : " + userName;
log.error(msg, e);
throw IdentityException.error(msg, e);
}
}
/**
* get email address from user store
*
* @param userName user name
* @param tenantId tenant id
* @return email address
*/
public static String getEmailAddressForUser(String userName, int tenantId) {
String email = null;
try {
if (log.isDebugEnabled()) {
log.debug("Retrieving email address from user profile.");
}
Tenant tenant = IdentityMgtServiceComponent.getRealmService().
getTenantManager().getTenant(tenantId);
if (tenant != null && tenant.getAdminName().equals(userName)) {
email = tenant.getEmail();
}
if (email == null || email.trim().length() < 1) {
email = getClaimFromUserStoreManager(userName, tenantId,
UserCoreConstants.ClaimTypeURIs.EMAIL_ADDRESS);
}
if ((email == null || email.trim().length() < 1) && MultitenantUtils.isEmailUserName()) {
email = UserCoreUtil.removeDomainFromName(userName);
}
} catch (Exception e) {
String msg = "Unable to retrieve an email address associated with the given user : " + userName;
log.warn(msg, e); // It is common to have users with no email address defined.
}
return email;
}
/**
* Update Password with the user input
*
* @return true - if password was successfully reset
* @throws IdentityException
*/
public static boolean updatePassword(String userId, int tenantId, String password) throws IdentityException {
String tenantDomain = null;
if (userId == null || userId.trim().length() < 1 ||
password == null || password.trim().length() < 1) {
String msg = "Unable to find the required information for updating password";
log.error(msg);
throw IdentityException.error(msg);
}
try {
UserStoreManager userStoreManager = IdentityMgtServiceComponent.
getRealmService().getTenantUserRealm(tenantId).getUserStoreManager();
userStoreManager.updateCredentialByAdmin(userId, password);
if (log.isDebugEnabled()) {
String msg = "Password is updated for user: " + userId;
log.debug(msg);
}
return true;
} catch (UserStoreException e) {
String msg = "Error in changing the password, user name: " + userId + " domain: " +
tenantDomain + ".";
log.error(msg, e);
throw IdentityException.error(msg, e);
}
}
/**
* @param value
* @return
* @throws UserStoreException
*/
public static String doHash(String value) throws UserStoreException {
try {
String digsestFunction = "SHA-256";
MessageDigest dgst = MessageDigest.getInstance(digsestFunction);
byte[] byteValue = dgst.digest(value.getBytes());
return Base64.encode(byteValue);
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage(), e);
throw new UserStoreException(e.getMessage(), e);
}
}
/**
* Set claim to user store manager
*
* @param userName user name
* @param tenantId tenant id
* @param claim claim uri
* @param value claim value
* @throws IdentityException if fails
*/
public static void setClaimInUserStoreManager(String userName, int tenantId, String claim,
String value) throws IdentityException {
org.wso2.carbon.user.core.UserStoreManager userStoreManager = null;
RealmService realmService = IdentityMgtServiceComponent.getRealmService();
try {
if (realmService.getTenantUserRealm(tenantId) != null) {
userStoreManager = (org.wso2.carbon.user.core.UserStoreManager) realmService.getTenantUserRealm(tenantId).
getUserStoreManager();
}
} catch (Exception e) {
String msg = "Error retrieving the user store manager for the tenant";
log.error(msg, e);
throw IdentityException.error(msg, e);
}
try {
if (userStoreManager != null) {
String oldValue = userStoreManager.getUserClaimValue(userName, claim, null);
if (oldValue == null || !oldValue.equals(value)) {
Map<String,String> claimMap = new HashMap<String,String>();
claimMap.put(claim, value);
userStoreManager.setUserClaimValues(userName, claimMap, UserCoreConstants.DEFAULT_PROFILE);
}
}
} catch (Exception e) {
String msg = "Unable to set the claim for user : " + userName;
log.error(msg, e);
throw IdentityException.error(msg, e);
}
}
public static String getUserStoreDomainName(String userName) {
int index;
String userDomain;
if ((index = userName.indexOf(CarbonConstants.DOMAIN_SEPARATOR)) >= 0) {
// remove domain name if exist
userDomain = userName.substring(0, index);
} else {
userDomain = UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME;
}
return userDomain;
}
public static String[] getChallengeUris() {
//TODO
return new String[]{IdentityMgtConstants.DEFAULT_CHALLENGE_QUESTION_URI01,
IdentityMgtConstants.DEFAULT_CHALLENGE_QUESTION_URI02};
}
public static Policy getSecurityPolicy() {
String policyString = " <wsp:Policy wsu:Id=\"UTOverTransport\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\"\n" +
" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">\n" +
" <wsp:ExactlyOne>\n" +
" <wsp:All>\n" +
" <sp:TransportBinding xmlns:sp=\"http://schemas.xmlsoap.org/ws/2005/07/securitypolicy\">\n" +
" <wsp:Policy>\n" +
" <sp:TransportToken>\n" +
" <wsp:Policy>\n" +
" <sp:HttpsToken RequireClientCertificate=\"true\"/>\n" +
" </wsp:Policy>\n" +
" </sp:TransportToken>\n" +
" <sp:AlgorithmSuite>\n" +
" <wsp:Policy>\n" +
" <sp:Basic256/>\n" +
" </wsp:Policy>\n" +
" </sp:AlgorithmSuite>\n" +
" <sp:Layout>\n" +
" <wsp:Policy>\n" +
" <sp:Lax/>\n" +
" </wsp:Policy>\n" +
" </sp:Layout>\n" +
" <sp:IncludeTimestamp/>\n" +
" </wsp:Policy>\n" +
" </sp:TransportBinding>\n" +
" </wsp:All>\n" +
" </wsp:ExactlyOne>\n" +
" </wsp:Policy>";
return PolicyEngine.getPolicy(new ByteArrayInputStream(policyString.getBytes()));
}
}