com.sun.identity.console.user.model.UMChangeUserPasswordModelImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.sun.identity.console.user.model.UMChangeUserPasswordModelImpl.java

Source

/**
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2007 Sun Microsystems Inc. All Rights Reserved
 *
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at
 * https://opensso.dev.java.net/public/CDDLv1.0.html or
 * opensso/legal/CDDLv1.0.txt
 * See the License for the specific language governing
 * permission and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at opensso/legal/CDDLv1.0.txt.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * $Id$
 *
 */

package com.sun.identity.console.user.model;

import com.iplanet.am.sdk.AMHashMap;
import com.iplanet.sso.SSOException;
import com.sun.identity.console.base.model.AMAdminConstants;
import com.sun.identity.console.base.model.AMConsoleException;
import com.sun.identity.console.base.model.AMModelBase;
import com.sun.identity.idm.AMIdentity;
import com.sun.identity.idm.IdRepoException;
import com.sun.identity.idm.IdUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.binary.Base64;

/* - LOG COMPLETE - */

public class UMChangeUserPasswordModelImpl extends AMModelBase implements UMChangeUserPasswordModel {

    public static final String TOLVEN_CREDENTIAL_FORMAT_PKCS12 = "pkcs12";
    public static final String USERPKCS12_BINARY_ATTRNAME = "userPKCS12";

    public UMChangeUserPasswordModelImpl(HttpServletRequest req, Map map) {
        super(req, map);
    }

    /**
     * Returns user name.
     *
     * @param userId Universal ID of user.
     * @return user name.
     */
    public String getUserName(String userId) {
        String userName = "";
        try {
            AMIdentity amid = IdUtils.getIdentity(getUserSSOToken(), userId);
            userName = amid.getName();
        } catch (IdRepoException e) {
            debug.warning("UMChangeUserPasswordModelImpl.getUserName", e);
        }
        return userName;
    }

    /** 
     * Returns user password.
     *
     * @param userId Universal ID of user.
     * @return user password.
     * @throws AMConsoleException if password cannot be obtained.
     */
    public String getPassword(String userId) throws AMConsoleException {
        String password = "";
        String[] params = { userId, AMAdminConstants.ATTR_USER_PASSWORD };

        try {
            logEvent("ATTEMPT_READ_IDENTITY_ATTRIBUTE_VALUE", params);
            AMIdentity amid = IdUtils.getIdentity(getUserSSOToken(), userId);
            Set set = amid.getAttribute(AMAdminConstants.ATTR_USER_PASSWORD);

            if ((set != null) && !set.isEmpty()) {
                password = (String) set.iterator().next();
            }

            logEvent("SUCCEED_READ_IDENTITY_ATTRIBUTE_VALUE", params);
        } catch (SSOException e) {
            String strError = getErrorString(e);
            String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_PASSWORD, strError };
            logEvent("SSO_EXCEPTION_READ_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
            throw new AMConsoleException(strError);
        } catch (IdRepoException e) {
            String strError = getErrorString(e);
            String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_PASSWORD, strError };
            logEvent("IDM_EXCEPTION_READ_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
            throw new AMConsoleException(strError);
        }

        return password;
    }

    /**
     * Modifies user password.
     *
     * @param userId Universal ID of user.
     * @param password New password.
     * @throws AMConsoleException if password cannot be modified.
     */
    public void changePassword(String userId, String password) throws AMConsoleException {
        String[] params = { userId, AMAdminConstants.ATTR_USER_PASSWORD };
        try {
            logEvent("ATTEMPT_MODIFY_IDENTITY_ATTRIBUTE_VALUE", params);

            AMIdentity amid = IdUtils.getIdentity(getUserSSOToken(), userId);
            Map map = new HashMap(2);
            Set set = new HashSet(2);
            set.add(password);
            map.put(AMAdminConstants.ATTR_USER_PASSWORD, set);
            amid.setAttributes(map);
            amid.store();

            logEvent("SUCCEED_MODIFY_IDENTITY_ATTRIBUTE_VALUE", params);
        } catch (SSOException e) {
            String strError = getErrorString(e);
            String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_PASSWORD, strError };
            logEvent("SSO_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
            throw new AMConsoleException(strError);
        } catch (IdRepoException e) {
            String strError = getErrorString(e);
            String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_PASSWORD, strError };
            logEvent("IDM_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
            throw new AMConsoleException(strError);
        }
    }

    public void changePwd(String userId, String oldPassword, String newPassword) throws AMConsoleException {
        String[] params = { userId, AMAdminConstants.ATTR_USER_OLD_PASSWORD };
        try {
            logEvent("ATTEMPT_MODIFY_IDENTITY_ATTRIBUTE_VALUE", params);
            AMIdentity amIdentity = IdUtils.getIdentity(getUserSSOToken(), userId);
            boolean verified = verifyOldPassword(amIdentity, userId, oldPassword.toCharArray());
            if (!verified) {
                String strError = "Authorized for password changed denied";
                String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_OLD_PASSWORD, strError };
                logEvent("SSO_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
                throw new AMConsoleException(strError);
            }
            Map passwordMap = new AMHashMap(2);
            Set set = new HashSet(2);
            set.add(newPassword);
            passwordMap.put(AMAdminConstants.ATTR_USER_PASSWORD, set);
            Set<String> attributeNames = new HashSet<String>();
            attributeNames.add(USERPKCS12_BINARY_ATTRNAME);
            Map<String, byte[][]> userPKCS12Map = amIdentity.getBinaryAttributes(attributeNames);
            if (userPKCS12Map != null && userPKCS12Map.get(USERPKCS12_BINARY_ATTRNAME) != null) {
                KeyStore keyStore = null;
                try {
                    keyStore = KeyStore.getInstance(TOLVEN_CREDENTIAL_FORMAT_PKCS12);
                } catch (Exception e) {
                    String strError = "Could not get an instance of KeyStore to create user KeyStore: "
                            + getErrorString(e);
                    String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_OLD_PASSWORD, strError };
                    logEvent("SSO_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
                    throw new AMConsoleException(strError);
                }
                byte[][] oldUserPKCS12ByteArrs = (byte[][]) userPKCS12Map.get(USERPKCS12_BINARY_ATTRNAME);
                byte[] oldUserPKCS12 = oldUserPKCS12ByteArrs[0];
                ByteArrayInputStream bais = new ByteArrayInputStream(oldUserPKCS12);
                try {
                    keyStore.load(bais, oldPassword.toCharArray());
                } catch (Exception e) {
                    String strError = "Could not get user KeyStore using old password: " + getErrorString(e);
                    String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_OLD_PASSWORD, strError };
                    logEvent("SSO_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
                    throw new AMConsoleException(strError);
                }
                ByteArrayOutputStream baos = null;
                try {
                    String alias = keyStore.aliases().nextElement();
                    PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, oldPassword.toCharArray());
                    keyStore.setKeyEntry(alias, privateKey, newPassword.toCharArray(),
                            keyStore.getCertificateChain(alias));
                    baos = new ByteArrayOutputStream();
                } catch (Exception e) {
                    String strError = "Could not get Key from user KeyStore: " + getErrorString(e);
                    String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_OLD_PASSWORD, strError };
                    logEvent("SSO_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
                    throw new AMConsoleException(strError);
                }
                try {
                    keyStore.store(baos, newPassword.toCharArray());
                } catch (Exception e) {
                    String strError = "Could not save user KeyStore: " + getErrorString(e);
                    String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_OLD_PASSWORD, strError };
                    logEvent("SSO_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
                    throw new AMConsoleException(strError);
                }
                byte[] newUserPKCS12 = baos.toByteArray();
                byte[][] newUserPKCS12ByteArrs = new byte[1][];
                newUserPKCS12ByteArrs[0] = newUserPKCS12;
                Map<String, byte[][]> newUserPKCS12Map = newUserPKCS12Map = new HashMap<String, byte[][]>();
                newUserPKCS12Map.put(USERPKCS12_BINARY_ATTRNAME, newUserPKCS12ByteArrs);
                // Ensure that the following two lines are never out of sync (one would expect store() to be a transaction)
                amIdentity.setBinaryAttributes(newUserPKCS12Map);
                amIdentity.setAttributes(passwordMap);
                amIdentity.store();
            } else {
                amIdentity.setAttributes(passwordMap);
                amIdentity.store();
            }
            logEvent("SUCCEED_MODIFY_IDENTITY_ATTRIBUTE_VALUE", params);
        } catch (SSOException e) {
            String strError = getErrorString(e);
            String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_OLD_PASSWORD, strError };
            logEvent("SSO_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
            throw new AMConsoleException(strError);
        } catch (IdRepoException e) {
            String strError = getErrorString(e);
            String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_OLD_PASSWORD, strError };
            logEvent("IDM_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
            throw new AMConsoleException(strError);
        }
    }

    private boolean verifyOldPassword(AMIdentity amIdentity, String userId, char[] oldPassword)
            throws AMConsoleException {
        Set<String> userPasswordSet = null;
        try {
            userPasswordSet = amIdentity.getAttribute("userPassword");
        } catch (Exception ex) {
            String strError = "Authorized for password changed denied: " + getErrorString(ex);
            String[] paramsEx = { userId, AMAdminConstants.ATTR_USER_OLD_PASSWORD, strError };
            logEvent("SSO_EXCEPTION_MODIFY_IDENTITY_ATTRIBUTE_VALUE", paramsEx);
            throw new AMConsoleException(strError);
        }
        if (userPasswordSet == null || userPasswordSet.isEmpty()) {

        }
        String sshaPasswordString = (String) userPasswordSet.iterator().next();
        return checkPassword(oldPassword, sshaPasswordString);
    }

    private boolean checkPassword(char[] password, String sshaPasswordString) {
        byte[] passwordBytes = getBytes(password);
        return checkPassword(passwordBytes, sshaPasswordString);
    }

    private byte[] getBytes(char[] charArr) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            OutputStreamWriter outputStreamWriter = null;
            try {
                outputStreamWriter = new OutputStreamWriter(baos);
                outputStreamWriter.write(charArr, 0, charArr.length);
            } finally {
                if (outputStreamWriter != null) {
                    outputStreamWriter.close();
                }
            }
            return baos.toByteArray();
        } catch (IOException ex) {
            throw new RuntimeException("Could not convert char[] to byte[]", ex);
        }
    }

    /**
     * Check the supplied plaintext password against the supplied hashed SSHA password.
     * @param password
     * @param sshaPasswordString
     * @return true if the password compares true
     */
    private boolean checkPassword(byte[] password, String sshaPasswordString) {

        if (!sshaPasswordString.startsWith("{SSHA}"))
            return false;
        byte[] digestPlusSalt = Base64.decodeBase64(sshaPasswordString.substring(6).getBytes());
        byte[] salt = new byte[8];
        byte[] digestBytes = new byte[digestPlusSalt.length - 8];

        System.arraycopy(digestPlusSalt, 0, digestBytes, 0, digestBytes.length);
        System.arraycopy(digestPlusSalt, digestBytes.length, salt, 0, salt.length);

        byte[] passwordPlusSalt = new byte[password.length + salt.length];
        System.arraycopy(password, 0, passwordPlusSalt, 0, password.length);
        System.arraycopy(salt, 0, passwordPlusSalt, password.length, salt.length);

        MessageDigest sha1Digest = null;
        try {
            sha1Digest = MessageDigest.getInstance("SHA-1");
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException("Could not get an SHA-1 MessageDigest instance to encode a password", ex);
        }
        byte[] passwordPlusSaltHash = sha1Digest.digest(passwordPlusSalt);

        return Arrays.equals(digestBytes, passwordPlusSaltHash);
    }

}