diff options
author | Robert Godfrey <rgodfrey@apache.org> | 2014-07-06 21:28:20 +0000 |
---|---|---|
committer | Robert Godfrey <rgodfrey@apache.org> | 2014-07-06 21:28:20 +0000 |
commit | 33c44bd0d25c4fb082a48820e5b2ced20e29c0b2 (patch) | |
tree | 3a96b4f453af0fa11aab2f82269bb01c4fe58d72 /java/broker-core/src | |
parent | 7f4550b66619ed14378c188972e72c319c79f9bc (diff) | |
download | qpid-python-33c44bd0d25c4fb082a48820e5b2ced20e29c0b2.tar.gz |
QPID-5878 : [Java Broker] Add SCRAM-SHA-256 SASL support
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@1608295 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/broker-core/src')
-rw-r--r-- | java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java | 3 | ||||
-rw-r--r-- | java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java | 397 | ||||
-rw-r--r-- | java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java | 4 | ||||
-rw-r--r-- | java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManager.java | 349 | ||||
-rw-r--r-- | java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA256AuthenticationManager.java | 66 | ||||
-rw-r--r-- | java/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServer.java (renamed from java/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSHA1SaslServer.java) | 49 |
6 files changed, 505 insertions, 363 deletions
diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java index 597b9e3bb1..a2bb5cb91a 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java @@ -26,7 +26,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import org.apache.log4j.Logger; @@ -148,8 +147,6 @@ public abstract class AbstractAuthenticationManager<T extends AbstractAuthentica if(childClass == PreferencesProvider.class) { attributes = new HashMap<String, Object>(attributes); - attributes.put(ConfiguredObject.ID, UUID.randomUUID()); - attributes.put(ConfiguredObject.DESIRED_STATE, State.ACTIVE); PreferencesProvider pp = getObjectFactory().create(PreferencesProvider.class, attributes, this); _preferencesProvider = pp; diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java new file mode 100644 index 0000000000..f08c37008a --- /dev/null +++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java @@ -0,0 +1,397 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.qpid.server.security.auth.manager; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.xml.bind.DatatypeConverter; + +import org.apache.qpid.server.configuration.updater.Task; +import org.apache.qpid.server.configuration.updater.VoidTaskWithException; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.User; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.scram.ScramSaslServer; + +public abstract class AbstractScramAuthenticationManager<X extends AbstractScramAuthenticationManager<X>> + extends AbstractAuthenticationManager<X> + implements PasswordCredentialManagingAuthenticationProvider<X> +{ + public static final String SCRAM_USER_TYPE = "scram"; + + static final Charset ASCII = Charset.forName("ASCII"); + private final SecureRandom _random = new SecureRandom(); + + private int _iterationCount = 4096; + + private Map<String, ScramAuthUser> _users = new ConcurrentHashMap<String, ScramAuthUser>(); + + + protected AbstractScramAuthenticationManager(final Map<String, Object> attributes, final Broker broker) + { + super(attributes, broker); + } + + @Override + public void initialise() + { + + } + + @Override + public String getMechanisms() + { + return getMechanismName(); + } + + protected abstract String getMechanismName(); + + @Override + public SaslServer createSaslServer(final String mechanism, + final String localFQDN, + final Principal externalPrincipal) + throws SaslException + { + return new ScramSaslServer(this, getMechanismName(), getHmacName(), getDigestName()); + } + + protected abstract String getDigestName(); + + @Override + public AuthenticationResult authenticate(final SaslServer server, final byte[] response) + { + try + { + // Process response from the client + byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]); + + if (server.isComplete()) + { + final String userId = server.getAuthorizationID(); + return new AuthenticationResult(new UsernamePrincipal(userId)); + } + else + { + return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE); + } + } + catch (SaslException e) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); + } + } + + @Override + public AuthenticationResult authenticate(final String username, final String password) + { + ScramAuthUser user = getUser(username); + if(user != null) + { + final String[] usernamePassword = user.getPassword().split(","); + byte[] salt = DatatypeConverter.parseBase64Binary(usernamePassword[0]); + try + { + if(Arrays.equals(DatatypeConverter.parseBase64Binary(usernamePassword[1]), + createSaltedPassword(salt, password))) + { + return new AuthenticationResult(new UsernamePrincipal(username)); + } + } + catch (SaslException e) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR,e); + } + + } + + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); + + + } + + + public int getIterationCount() + { + return _iterationCount; + } + + public byte[] getSalt(final String username) + { + ScramAuthUser user = getUser(username); + + if(user == null) + { + // don't disclose that the user doesn't exist, just generate random data so the failure is indistinguishable + // from the "wrong password" case + + byte[] salt = new byte[32]; + _random.nextBytes(salt); + return salt; + } + else + { + return DatatypeConverter.parseBase64Binary(user.getPassword().split(",")[0]); + } + } + + private static final byte[] INT_1 = new byte[]{0, 0, 0, 1}; + + public byte[] getSaltedPassword(final String username) throws SaslException + { + ScramAuthUser user = getUser(username); + if(user == null) + { + throw new SaslException("Authentication Failed"); + } + else + { + return DatatypeConverter.parseBase64Binary(user.getPassword().split(",")[1]); + } + } + + private ScramAuthUser getUser(final String username) + { + return _users.get(username); + } + + private byte[] createSaltedPassword(byte[] salt, String password) throws SaslException + { + Mac mac = createSha1Hmac(password.getBytes(ASCII)); + + mac.update(salt); + mac.update(INT_1); + byte[] result = mac.doFinal(); + + byte[] previous = null; + for(int i = 1; i < getIterationCount(); i++) + { + mac.update(previous != null? previous: result); + previous = mac.doFinal(); + for(int x = 0; x < result.length; x++) + { + result[x] ^= previous[x]; + } + } + + return result; + + } + + private Mac createSha1Hmac(final byte[] keyBytes) + throws SaslException + { + try + { + SecretKeySpec key = new SecretKeySpec(keyBytes, getHmacName()); + Mac mac = Mac.getInstance(getHmacName()); + mac.init(key); + return mac; + } + catch (NoSuchAlgorithmException e) + { + throw new SaslException(e.getMessage(), e); + } + catch (InvalidKeyException e) + { + throw new SaslException(e.getMessage(), e); + } + } + + protected abstract String getHmacName(); + + @Override + public boolean createUser(final String username, final String password, final Map<String, String> attributes) + { + return runTask(new Task<Boolean>() + { + @Override + public Boolean execute() + { + getSecurityManager().authoriseUserOperation(Operation.CREATE, username); + if (_users.containsKey(username)) + { + throw new IllegalArgumentException("User '" + username + "' already exists"); + } + try + { + Map<String, Object> userAttrs = new HashMap<String, Object>(); + userAttrs.put(User.ID, UUID.randomUUID()); + userAttrs.put(User.NAME, username); + userAttrs.put(User.PASSWORD, createStoredPassword(password)); + userAttrs.put(User.TYPE, SCRAM_USER_TYPE); + ScramAuthUser user = new ScramAuthUser(userAttrs, AbstractScramAuthenticationManager.this); + user.create(); + + return true; + } + catch (SaslException e) + { + throw new IllegalArgumentException(e); + } + } + }); + } + + org.apache.qpid.server.security.SecurityManager getSecurityManager() + { + return getBroker().getSecurityManager(); + } + + @Override + public void deleteUser(final String user) throws AccountNotFoundException + { + runTask(new VoidTaskWithException<AccountNotFoundException>() + { + @Override + public void execute() throws AccountNotFoundException + { + final ScramAuthUser authUser = getUser(user); + if(authUser != null) + { + authUser.setState(State.DELETED); + } + else + { + throw new AccountNotFoundException("No such user: '" + user + "'"); + } + } + }); + } + + @Override + public void setPassword(final String username, final String password) throws AccountNotFoundException + { + runTask(new VoidTaskWithException<AccountNotFoundException>() + { + @Override + public void execute() throws AccountNotFoundException + { + + final ScramAuthUser authUser = getUser(username); + if (authUser != null) + { + authUser.setPassword(password); + } + else + { + throw new AccountNotFoundException("No such user: '" + username + "'"); + } + } + }); + + } + + @Override + public Map<String, Map<String, String>> getUsers() + { + return runTask(new Task<Map<String, Map<String, String>>>() + { + @Override + public Map<String, Map<String, String>> execute() + { + + Map<String, Map<String, String>> users = new HashMap<String, Map<String, String>>(); + for (String user : _users.keySet()) + { + users.put(user, Collections.<String, String>emptyMap()); + } + return users; + } + }); + } + + @Override + public void reload() throws IOException + { + + } + + @Override + public void recoverUser(final User user) + { + _users.put(user.getName(), (ScramAuthUser) user); + } + + protected String createStoredPassword(final String password) throws SaslException + { + byte[] salt = new byte[32]; + _random.nextBytes(salt); + byte[] passwordBytes = createSaltedPassword(salt, password); + return DatatypeConverter.printBase64Binary(salt) + "," + DatatypeConverter.printBase64Binary(passwordBytes); + } + + @Override + public <C extends ConfiguredObject> C addChild(final Class<C> childClass, + final Map<String, Object> attributes, + final ConfiguredObject... otherParents) + { + if(childClass == User.class) + { + String username = (String) attributes.get("name"); + String password = (String) attributes.get("password"); + + if(createUser(username, password,null)) + { + @SuppressWarnings("unchecked") + C user = (C) _users.get(username); + return user; + } + else + { + return null; + + } + } + return super.addChild(childClass, attributes, otherParents); + } + + void doDeleted() + { + deleted(); + } + + Map<String, ScramAuthUser> getUserMap() + { + return _users; + } + +} diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java index 15cd1d82a6..9a2d27f512 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java @@ -44,12 +44,12 @@ import org.apache.qpid.server.security.access.Operation; class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements User<ScramAuthUser> { - private ScramSHA1AuthenticationManager _authenticationManager; + private AbstractScramAuthenticationManager _authenticationManager; @ManagedAttributeField private String _password; @ManagedObjectFactoryConstructor - ScramAuthUser(final Map<String, Object> attributes, ScramSHA1AuthenticationManager parent) + ScramAuthUser(final Map<String, Object> attributes, AbstractScramAuthenticationManager parent) { super(parentsMap(parent), attributes); _authenticationManager = parent; diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManager.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManager.java index 2138f4899e..6a48d29a71 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManager.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManager.java @@ -20,53 +20,23 @@ */ package org.apache.qpid.server.security.auth.manager; -import java.io.IOException; import java.nio.charset.Charset; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.xml.bind.DatatypeConverter; - -import org.apache.qpid.server.configuration.updater.Task; -import org.apache.qpid.server.configuration.updater.VoidTaskWithException; import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; -import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.User; -import org.apache.qpid.server.security.SecurityManager; -import org.apache.qpid.server.security.access.Operation; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.security.auth.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.scram.ScramSHA1SaslServer; @ManagedObject( category = false, type = "SCRAM-SHA-1" ) public class ScramSHA1AuthenticationManager - extends AbstractAuthenticationManager<ScramSHA1AuthenticationManager> - implements PasswordCredentialManagingAuthenticationProvider<ScramSHA1AuthenticationManager> + extends AbstractScramAuthenticationManager<ScramSHA1AuthenticationManager> { - public static final String SCRAM_USER_TYPE = "scram"; public static final String PROVIDER_TYPE = "SCRAM-SHA-1"; + private static final String HMAC_NAME = "HmacSHA1"; + static final Charset ASCII = Charset.forName("ASCII"); - public static final String HMAC_SHA_1 = "HmacSHA1"; - private final SecureRandom _random = new SecureRandom(); - private int _iterationCount = 4096; - private Map<String, ScramAuthUser> _users = new ConcurrentHashMap<String, ScramAuthUser>(); + private static final String MECHANISM = "SCRAM-SHA-1"; + private static final String DIGEST_NAME = "SHA-1"; @ManagedObjectFactoryConstructor @@ -76,318 +46,21 @@ public class ScramSHA1AuthenticationManager } @Override - public void initialise() - { - - } - - @Override - public String getMechanisms() - { - return ScramSHA1SaslServer.MECHANISM; - } - - @Override - public SaslServer createSaslServer(final String mechanism, - final String localFQDN, - final Principal externalPrincipal) - throws SaslException - { - return new ScramSHA1SaslServer(this); - } - - @Override - public AuthenticationResult authenticate(final SaslServer server, final byte[] response) - { - try - { - // Process response from the client - byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]); - - if (server.isComplete()) - { - final String userId = server.getAuthorizationID(); - return new AuthenticationResult(new UsernamePrincipal(userId)); - } - else - { - return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE); - } - } - catch (SaslException e) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); - } - } - - @Override - public AuthenticationResult authenticate(final String username, final String password) - { - ScramAuthUser user = getUser(username); - if(user != null) - { - final String[] usernamePassword = user.getPassword().split(","); - byte[] salt = DatatypeConverter.parseBase64Binary(usernamePassword[0]); - try - { - if(Arrays.equals(DatatypeConverter.parseBase64Binary(usernamePassword[1]),createSaltedPassword(salt, password))) - { - return new AuthenticationResult(new UsernamePrincipal(username)); - } - } - catch (SaslException e) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR,e); - } - - } - - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); - - - } - - - public int getIterationCount() - { - return _iterationCount; - } - - public byte[] getSalt(final String username) - { - ScramAuthUser user = getUser(username); - - if(user == null) - { - // don't disclose that the user doesn't exist, just generate random data so the failure is indistinguishable - // from the "wrong password" case - - byte[] salt = new byte[32]; - _random.nextBytes(salt); - return salt; - } - else - { - return DatatypeConverter.parseBase64Binary(user.getPassword().split(",")[0]); - } - } - - private static final byte[] INT_1 = new byte[]{0, 0, 0, 1}; - - public byte[] getSaltedPassword(final String username) throws SaslException - { - ScramAuthUser user = getUser(username); - if(user == null) - { - throw new SaslException("Authentication Failed"); - } - else - { - return DatatypeConverter.parseBase64Binary(user.getPassword().split(",")[1]); - } - } - - private ScramAuthUser getUser(final String username) - { - return _users.get(username); - } - - private byte[] createSaltedPassword(byte[] salt, String password) throws SaslException - { - Mac mac = createSha1Hmac(password.getBytes(ASCII)); - - mac.update(salt); - mac.update(INT_1); - byte[] result = mac.doFinal(); - - byte[] previous = null; - for(int i = 1; i < getIterationCount(); i++) - { - mac.update(previous != null? previous: result); - previous = mac.doFinal(); - for(int x = 0; x < result.length; x++) - { - result[x] ^= previous[x]; - } - } - - return result; - - } - - private Mac createSha1Hmac(final byte[] keyBytes) - throws SaslException - { - try - { - SecretKeySpec key = new SecretKeySpec(keyBytes, HMAC_SHA_1); - Mac mac = Mac.getInstance(HMAC_SHA_1); - mac.init(key); - return mac; - } - catch (NoSuchAlgorithmException e) - { - throw new SaslException(e.getMessage(), e); - } - catch (InvalidKeyException e) - { - throw new SaslException(e.getMessage(), e); - } - } - - @Override - public boolean createUser(final String username, final String password, final Map<String, String> attributes) - { - return runTask(new Task<Boolean>() - { - @Override - public Boolean execute() - { - getSecurityManager().authoriseUserOperation(Operation.CREATE, username); - if (_users.containsKey(username)) - { - throw new IllegalArgumentException("User '" + username + "' already exists"); - } - try - { - Map<String, Object> userAttrs = new HashMap<String, Object>(); - userAttrs.put(User.ID, UUID.randomUUID()); - userAttrs.put(User.NAME, username); - userAttrs.put(User.PASSWORD, createStoredPassword(password)); - userAttrs.put(User.TYPE, SCRAM_USER_TYPE); - ScramAuthUser user = new ScramAuthUser(userAttrs, ScramSHA1AuthenticationManager.this); - user.create(); - - return true; - } - catch (SaslException e) - { - throw new IllegalArgumentException(e); - } - } - }); - } - - SecurityManager getSecurityManager() - { - return getBroker().getSecurityManager(); - } - - @Override - public void deleteUser(final String user) throws AccountNotFoundException - { - runTask(new VoidTaskWithException<AccountNotFoundException>() - { - @Override - public void execute() throws AccountNotFoundException - { - final ScramAuthUser authUser = getUser(user); - if(authUser != null) - { - authUser.setState(State.DELETED); - } - else - { - throw new AccountNotFoundException("No such user: '" + user + "'"); - } - } - }); - } - - @Override - public void setPassword(final String username, final String password) throws AccountNotFoundException + protected String getMechanismName() { - runTask(new VoidTaskWithException<AccountNotFoundException>() - { - @Override - public void execute() throws AccountNotFoundException - { - - final ScramAuthUser authUser = getUser(username); - if (authUser != null) - { - authUser.setPassword(password); - } - else - { - throw new AccountNotFoundException("No such user: '" + username + "'"); - } - } - }); - - } - - @Override - public Map<String, Map<String, String>> getUsers() - { - return runTask(new Task<Map<String, Map<String, String>>>() - { - @Override - public Map<String, Map<String, String>> execute() - { - - Map<String, Map<String, String>> users = new HashMap<String, Map<String, String>>(); - for (String user : _users.keySet()) - { - users.put(user, Collections.<String, String>emptyMap()); - } - return users; - } - }); - } - - @Override - public void reload() throws IOException - { - + return MECHANISM; } @Override - public void recoverUser(final User user) - { - _users.put(user.getName(), (ScramAuthUser) user); - } - - protected String createStoredPassword(final String password) throws SaslException + protected String getDigestName() { - byte[] salt = new byte[32]; - _random.nextBytes(salt); - byte[] passwordBytes = createSaltedPassword(salt, password); - return DatatypeConverter.printBase64Binary(salt) + "," + DatatypeConverter.printBase64Binary(passwordBytes); + return DIGEST_NAME; } @Override - public <C extends ConfiguredObject> C addChild(final Class<C> childClass, - final Map<String, Object> attributes, - final ConfiguredObject... otherParents) + protected String getHmacName() { - if(childClass == User.class) - { - String username = (String) attributes.get("name"); - String password = (String) attributes.get("password"); - - if(createUser(username, password,null)) - { - @SuppressWarnings("unchecked") - C user = (C) _users.get(username); - return user; - } - else - { - return null; - - } - } - return super.addChild(childClass, attributes, otherParents); + return HMAC_NAME; } - void doDeleted() - { - deleted(); - } - - Map<String, ScramAuthUser> getUserMap() - { - return _users; - } } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA256AuthenticationManager.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA256AuthenticationManager.java new file mode 100644 index 0000000000..ea5b82fdd5 --- /dev/null +++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA256AuthenticationManager.java @@ -0,0 +1,66 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.qpid.server.security.auth.manager; + +import java.nio.charset.Charset; +import java.util.Map; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ManagedObject; +import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; + +@ManagedObject( category = false, type = "SCRAM-SHA-256" ) +public class ScramSHA256AuthenticationManager + extends AbstractScramAuthenticationManager<ScramSHA256AuthenticationManager> +{ + public static final String PROVIDER_TYPE = "SCRAM-SHA-256"; + private static final String HMAC_NAME = "HmacSHA256"; + + static final Charset ASCII = Charset.forName("ASCII"); + private static final String MECHANISM = "SCRAM-SHA-256"; + private static final String DIGEST_NAME = "SHA-256"; + + + @ManagedObjectFactoryConstructor + protected ScramSHA256AuthenticationManager(final Map<String, Object> attributes, final Broker broker) + { + super(attributes, broker); + } + + @Override + protected String getMechanismName() + { + return MECHANISM; + } + + @Override + protected String getDigestName() + { + return DIGEST_NAME; + } + + @Override + protected String getHmacName() + { + return HMAC_NAME; + } + +} diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSHA1SaslServer.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServer.java index 71ef386e3e..f510ec32d8 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSHA1SaslServer.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServer.java @@ -20,13 +20,6 @@ */ package org.apache.qpid.server.security.auth.sasl.scram; -import org.apache.qpid.server.security.auth.manager.ScramSHA1AuthenticationManager; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.xml.bind.DatatypeConverter; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.security.InvalidKeyException; @@ -35,13 +28,23 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.UUID; -public class ScramSHA1SaslServer implements SaslServer +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.xml.bind.DatatypeConverter; + +import org.apache.qpid.server.security.auth.manager.AbstractScramAuthenticationManager; + +public class ScramSaslServer implements SaslServer { - public static final String MECHANISM = "SCRAM-SHA-1"; + public final String _mechanism; + public final String _hmacName; + public final String _digestName; private static final Charset ASCII = Charset.forName("ASCII"); - private final ScramSHA1AuthenticationManager _authManager; + private final AbstractScramAuthenticationManager _authManager; private State _state = State.INITIAL; private String _nonce; private String _username; @@ -50,9 +53,15 @@ public class ScramSHA1SaslServer implements SaslServer private String _clientFirstMessageBare; private byte[] _serverSignature; - public ScramSHA1SaslServer(final ScramSHA1AuthenticationManager authenticationManager) + public ScramSaslServer(final AbstractScramAuthenticationManager authenticationManager, + final String mechanism, + final String hmacName, + final String digestName) { _authManager = authenticationManager; + _mechanism = mechanism; + _hmacName = hmacName; + _digestName = digestName; } enum State @@ -65,7 +74,7 @@ public class ScramSHA1SaslServer implements SaslServer @Override public String getMechanismName() { - return MECHANISM; + return _mechanism; } @Override @@ -174,11 +183,11 @@ public class ScramSHA1SaslServer implements SaslServer byte[] saltedPassword = _authManager.getSaltedPassword(_username); - byte[] clientKey = computeHmacSHA1(saltedPassword, "Client Key"); + byte[] clientKey = computeHmac(saltedPassword, "Client Key"); - byte[] storedKey = MessageDigest.getInstance("SHA1").digest(clientKey); + byte[] storedKey = MessageDigest.getInstance(_digestName).digest(clientKey); - byte[] clientSignature = computeHmacSHA1(storedKey, authMessage); + byte[] clientSignature = computeHmac(storedKey, authMessage); byte[] clientProof = clientKey.clone(); for(int i = 0 ; i < clientProof.length; i++) @@ -190,8 +199,8 @@ public class ScramSHA1SaslServer implements SaslServer { throw new SaslException("Authentication failed"); } - byte[] serverKey = computeHmacSHA1(saltedPassword, "Server Key"); - String finalResponse = "v=" + DatatypeConverter.printBase64Binary(computeHmacSHA1(serverKey, authMessage)); + byte[] serverKey = computeHmac(saltedPassword, "Server Key"); + String finalResponse = "v=" + DatatypeConverter.printBase64Binary(computeHmac(serverKey, authMessage)); return finalResponse.getBytes(ASCII); } @@ -241,7 +250,7 @@ public class ScramSHA1SaslServer implements SaslServer } - private byte[] computeHmacSHA1(final byte[] key, final String string) + private byte[] computeHmac(final byte[] key, final String string) throws SaslException, UnsupportedEncodingException { Mac mac = createSha1Hmac(key); @@ -255,8 +264,8 @@ public class ScramSHA1SaslServer implements SaslServer { try { - SecretKeySpec key = new SecretKeySpec(keyBytes, "HmacSHA1"); - Mac mac = Mac.getInstance("HmacSHA1"); + SecretKeySpec key = new SecretKeySpec(keyBytes, _hmacName); + Mac mac = Mac.getInstance(_hmacName); mac.init(key); return mac; } |