/************************************************************************* * * * SignServer: The OpenSource Automated Signing Server * * * * This software is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or any later version. * * * * See terms of license at gnu.org. * * * *************************************************************************/ package org.signserver.server; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.EntityManager; import org.apache.log4j.Logger; import org.bouncycastle.util.encoders.Hex; import org.signserver.common.AuthorizationRequiredException; import org.signserver.common.IllegalRequestException; import org.signserver.common.ProcessRequest; import org.signserver.common.RequestContext; import org.signserver.common.SignServerException; import org.signserver.common.WorkerConfig; import org.signserver.server.log.LogMap; /** * Authorizer requiring a username password pair. * * @version $Id: UsernamePasswordAuthorizer.java 2966 2012-11-09 10:30:48Z netmackan $ */ public class UsernamePasswordAuthorizer implements IAuthorizer { /** Logger for this class. */ private static final Logger LOG = Logger.getLogger( UsernamePasswordAuthorizer.class); /** * Format for a user entry is: *
     * USER.[NAME] = [PASSWORD]
     * USER.[NAME] = [HASHED_PASSWORD]:[HASH_ALGORITHM]
     * USER.[NAME] = [HASHED_PASSWORD]:[HASH_ALGORITHM]:[SALT]
     * 
* SALT and HASH_ALGORITHM are optionally. */ private static final String USER_PREFIX = "USER."; private Map userMap = Collections.emptyMap(); @Override public void init(final int workerId, final WorkerConfig config, final EntityManager em) throws SignServerException { loadAccounts(config); } @Override public List getFatalErrors() { return Collections.emptyList(); } @Override public void isAuthorized(final ProcessRequest request, final RequestContext requestContext) throws SignServerException, IllegalRequestException { final Object o = requestContext.get(RequestContext.CLIENT_CREDENTIAL); if (o instanceof UsernamePasswordClientCredential) { if (!isAuthorized((UsernamePasswordClientCredential) o)) { throw new AuthorizationRequiredException( "Authentication denied"); } // Put the authorized username in the log logUsername(((UsernamePasswordClientCredential) o).getUsername(), requestContext); } else { throw new AuthorizationRequiredException( "Username/password authentication required"); } } private void loadAccounts(final WorkerConfig config) { userMap = new HashMap(); for(Object o : config.getProperties().keySet()) { if (o instanceof String) { final String key = (String) o; if (key.startsWith(USER_PREFIX) && key.length() > USER_PREFIX.length()) { final String value = config.getProperties().getProperty(key); final String[] parts = value.split(":"); final String password; String digestAlgorithm = null; final MessageDigest digest; String salt = ""; password = parts[0]; if (parts.length > 1) { digestAlgorithm = parts[1]; if (parts.length > 2) { salt = parts[2]; } } try { if (LOG.isDebugEnabled()) { LOG.debug("Loading account: " + key); } digest = digestAlgorithm == null ? null : MessageDigest.getInstance(digestAlgorithm, "BC"); userMap.put(key.substring(USER_PREFIX.length()).toUpperCase(), new Account(password, salt, digest)); } catch (NoSuchAlgorithmException ex) { LOG.error("Unsupported digest algorithm: " + digestAlgorithm, ex); } catch (NoSuchProviderException ex) { LOG.error("No BC provider getting digest algorithm", ex); } } } } } private boolean isAuthorized( final UsernamePasswordClientCredential credential) { final boolean result; if (credential.getUsername() == null || credential.getUsername().isEmpty()) { result = false; } else { final Account a = userMap.get(credential.getUsername().toUpperCase()); if (a == null) { if (LOG.isInfoEnabled()) { LOG.info("No such user: " + credential.getUsername()); } result = false; } else { String password = credential.getPassword() + a.getSalt(); if (a.getDigest() != null) { a.getDigest().reset(); password = new String(Hex.encode(a.getDigest().digest(password.getBytes()))); } result = password.equals(a.getPassword()); } } return result; } private static void logUsername(final String username, final RequestContext requestContext) { LogMap.getInstance(requestContext).put(IAuthorizer.LOG_USERNAME, username); } private static class Account { private String password; private String salt; private MessageDigest digest; public Account(final String password, final String salt, final MessageDigest digest) { this.password = password; this.salt = salt; this.digest = digest; } public MessageDigest getDigest() { return digest; } public String getPassword() { return password; } public String getSalt() { return salt; } } }