Commit 2cd0137f authored by Guus der Kinderen's avatar Guus der Kinderen

OF-1097: Reduce complexity of AuthProvider

AuthProvider has quite some complexity that exists solely for XEP-0078.
This commit removes most of that, by replacing the generic checks for
digest and plain support with a non-generic implementation, that will
work for any auth provider that supports password retrieval.
parent 667cd414
...@@ -24,6 +24,7 @@ import java.security.MessageDigest; ...@@ -24,6 +24,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Map; import java.util.Map;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.lockout.LockOutManager; import org.jivesoftware.openfire.lockout.LockOutManager;
import org.jivesoftware.openfire.user.UserNotFoundException; import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.Blowfish; import org.jivesoftware.util.Blowfish;
...@@ -146,27 +147,6 @@ public class AuthFactory { ...@@ -146,27 +147,6 @@ public class AuthFactory {
return authProvider.supportsPasswordRetrieval(); return authProvider.supportsPasswordRetrieval();
} }
/**
* Returns true if the currently installed {@link AuthProvider} supports authentication
* using plain-text passwords according to JEP-0078. Plain-text authentication is
* not secure and should generally only be used over a TLS/SSL connection.
*
* @return true if plain text password authentication is supported.
*/
public static boolean isPlainSupported() {
return authProvider.isPlainSupported();
}
/**
* Returns true if the currently installed {@link AuthProvider} supports
* digest authentication according to JEP-0078.
*
* @return true if digest authentication is supported.
*/
public static boolean isDigestSupported() {
return authProvider.isDigestSupported();
}
/** /**
* Returns the user's password. This method will throw an UnsupportedOperationException * Returns the user's password. This method will throw an UnsupportedOperationException
* if this operation is not supported by the backend user store. * if this operation is not supported by the backend user store.
...@@ -218,30 +198,6 @@ public class AuthFactory { ...@@ -218,30 +198,6 @@ public class AuthFactory {
return new AuthToken(username); return new AuthToken(username);
} }
/**
* Authenticates a user with a username, token, and digest and returns an AuthToken.
* The digest should be generated using the {@link #createDigest(String, String)} method.
* If the username and digest do not match the record of any user in the system, the
* method throws an UnauthorizedException.
*
* @param username the username.
* @param token the token that was used with plain-text password to generate the digest.
* @param digest the digest generated from plain-text password and unique token.
* @return an AuthToken token if the username and digest are correct for the user's
* password and given token.
* @throws UnauthorizedException if the username and password do not match any
* existing user or the account is locked out.
*/
public static AuthToken authenticate(String username, String token, String digest)
throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {
if (LockOutManager.getInstance().isAccountDisabled(username)) {
LockOutManager.getInstance().recordFailedLogin(username);
throw new UnauthorizedException();
}
authProvider.authenticate(username, token, digest);
return new AuthToken(username);
}
/** /**
* Returns a digest given a token and password, according to JEP-0078. * Returns a digest given a token and password, according to JEP-0078.
* *
......
...@@ -39,32 +39,10 @@ import org.jivesoftware.openfire.user.UserNotFoundException; ...@@ -39,32 +39,10 @@ import org.jivesoftware.openfire.user.UserNotFoundException;
*/ */
public interface AuthProvider { public interface AuthProvider {
/**
* Returns true if this AuthProvider supports authentication using plain-text
* passwords according to JEP--0078. Plain text authentication is not secure
* and should generally only be used for a TLS/SSL connection.
*
* @return true if plain text password authentication is supported by
* this AuthProvider.
*/
boolean isPlainSupported();
/**
* Returns true if this AuthProvider supports digest authentication
* according to JEP-0078.
*
* @return true if digest authentication is supported by this
* AuthProvider.
*/
boolean isDigestSupported();
/** /**
* Returns if the username and password are valid; otherwise this * Returns if the username and password are valid; otherwise this
* method throws an UnauthorizedException.<p> * method throws an UnauthorizedException.<p>
* *
* If {@link #isPlainSupported()} returns false, this method should
* throw an UnsupportedOperationException.
*
* @param username the username or full JID. * @param username the username or full JID.
* @param password the password * @param password the password
* @throws UnauthorizedException if the username and password do * @throws UnauthorizedException if the username and password do
...@@ -75,25 +53,6 @@ public interface AuthProvider { ...@@ -75,25 +53,6 @@ public interface AuthProvider {
void authenticate(String username, String password) throws UnauthorizedException, void authenticate(String username, String password) throws UnauthorizedException,
ConnectionException, InternalUnauthenticatedException; ConnectionException, InternalUnauthenticatedException;
/**
* Returns if the username, token, and digest are valid; otherwise this
* method throws an UnauthorizedException.<p>
*
* If {@link #isDigestSupported()} returns false, this method should
* throw an UnsupportedOperationException.
*
* @param username the username or full JID.
* @param token the token that was used with plain-text password to
* generate the digest.
* @param digest the digest generated from plain-text password and unique token.
* @throws UnauthorizedException if the username and password
* do not match any existing user.
* @throws ConnectionException it there is a problem connecting to user and group sytem
* @throws InternalUnauthenticatedException if there is a problem authentication Openfire iteself into the user and group system
*/
void authenticate(String username, String token, String digest)
throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException;
/** /**
* Returns the user's password. This method should throw an UnsupportedOperationException * Returns the user's password. This method should throw an UnsupportedOperationException
* if this operation is not supported by the backend user store. * if this operation is not supported by the backend user store.
......
...@@ -96,47 +96,6 @@ public class DefaultAuthProvider implements AuthProvider { ...@@ -96,47 +96,6 @@ public class DefaultAuthProvider implements AuthProvider {
// Got this far, so the user must be authorized. // Got this far, so the user must be authorized.
} }
@Override
public void authenticate(String username, String token, String digest) throws UnauthorizedException {
if (username == null || token == null || digest == null) {
throw new UnauthorizedException();
}
username = username.trim().toLowerCase();
if (username.contains("@")) {
// Check that the specified domain matches the server's domain
int index = username.indexOf("@");
String domain = username.substring(index + 1);
if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
username = username.substring(0, index);
} else {
// Unknown domain. Return authentication failed.
throw new UnauthorizedException();
}
}
try {
String password = getPassword(username);
String anticipatedDigest = AuthFactory.createDigest(token, password);
if (!digest.equalsIgnoreCase(anticipatedDigest)) {
throw new UnauthorizedException();
}
}
catch (UserNotFoundException unfe) {
throw new UnauthorizedException();
}
// Got this far, so the user must be authorized.
}
@Override
public boolean isPlainSupported() {
return true;
}
@Override
public boolean isDigestSupported() {
boolean scramOnly = JiveGlobals.getBooleanProperty("user.scramHashedPasswordOnly");
return !scramOnly;
}
@Override @Override
public String getPassword(String username) throws UserNotFoundException { public String getPassword(String username) throws UserNotFoundException {
if (!supportsPasswordRetrieval()) { if (!supportsPasswordRetrieval()) {
......
...@@ -106,13 +106,6 @@ public class HybridAuthProvider implements AuthProvider { ...@@ -106,13 +106,6 @@ public class HybridAuthProvider implements AuthProvider {
try { try {
Class c = ClassUtils.forName(primaryClass); Class c = ClassUtils.forName(primaryClass);
primaryProvider = (AuthProvider)c.newInstance(); primaryProvider = (AuthProvider)c.newInstance();
// All providers must support plain auth.
if (!primaryProvider.isPlainSupported()) {
Log.error("Provider " + primaryClass + " must support plain authentication. " +
"Authentication disabled.");
primaryProvider = null;
return;
}
Log.debug("Primary auth provider: " + primaryClass); Log.debug("Primary auth provider: " + primaryClass);
} }
catch (Exception e) { catch (Exception e) {
...@@ -127,14 +120,6 @@ public class HybridAuthProvider implements AuthProvider { ...@@ -127,14 +120,6 @@ public class HybridAuthProvider implements AuthProvider {
try { try {
Class c = ClassUtils.forName(secondaryClass); Class c = ClassUtils.forName(secondaryClass);
secondaryProvider = (AuthProvider)c.newInstance(); secondaryProvider = (AuthProvider)c.newInstance();
// All providers must support plain auth.
if (!secondaryProvider.isPlainSupported()) {
Log.error("Provider " + secondaryClass + " must support plain authentication. " +
"Authentication disabled.");
primaryProvider = null;
secondaryProvider = null;
return;
}
Log.debug("Secondary auth provider: " + secondaryClass); Log.debug("Secondary auth provider: " + secondaryClass);
} }
catch (Exception e) { catch (Exception e) {
...@@ -148,15 +133,6 @@ public class HybridAuthProvider implements AuthProvider { ...@@ -148,15 +133,6 @@ public class HybridAuthProvider implements AuthProvider {
try { try {
Class c = ClassUtils.forName(tertiaryClass); Class c = ClassUtils.forName(tertiaryClass);
tertiaryProvider = (AuthProvider)c.newInstance(); tertiaryProvider = (AuthProvider)c.newInstance();
// All providers must support plain auth.
if (!tertiaryProvider.isPlainSupported()) {
Log.error("Provider " + tertiaryClass + " must support plain authentication. " +
"Authentication disabled.");
primaryProvider = null;
secondaryProvider = null;
tertiaryProvider = null;
return;
}
Log.debug("Tertiary auth provider: " + tertiaryClass); Log.debug("Tertiary auth provider: " + tertiaryClass);
} }
catch (Exception e) { catch (Exception e) {
...@@ -188,16 +164,6 @@ public class HybridAuthProvider implements AuthProvider { ...@@ -188,16 +164,6 @@ public class HybridAuthProvider implements AuthProvider {
} }
} }
@Override
public boolean isPlainSupported() {
return true;
}
@Override
public boolean isDigestSupported() {
return false;
}
@Override @Override
public void authenticate(String username, String password) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException { public void authenticate(String username, String password) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {
// Check overrides first. // Check overrides first.
...@@ -238,13 +204,6 @@ public class HybridAuthProvider implements AuthProvider { ...@@ -238,13 +204,6 @@ public class HybridAuthProvider implements AuthProvider {
} }
} }
@Override
public void authenticate(String username, String token, String digest)
throws UnauthorizedException
{
throw new UnauthorizedException("Digest authentication not supported.");
}
@Override @Override
public String getPassword(String username) public String getPassword(String username)
throws UserNotFoundException, UnsupportedOperationException throws UserNotFoundException, UnsupportedOperationException
......
...@@ -257,57 +257,6 @@ public class JDBCAuthProvider implements AuthProvider, PropertyEventListener { ...@@ -257,57 +257,6 @@ public class JDBCAuthProvider implements AuthProvider, PropertyEventListener {
return password; return password;
} }
} }
@Override
public void authenticate(String username, String token, String digest)
throws UnauthorizedException
{
if (passwordTypes.size() != 1 || passwordTypes.get(0) != PasswordType.plain) {
throw new UnsupportedOperationException("Digest authentication not supported for "
+ "password type " + passwordTypes.get(0));
}
if (username == null || token == null || digest == null) {
throw new UnauthorizedException();
}
username = username.trim().toLowerCase();
if (username.contains("@")) {
// Check that the specified domain matches the server's domain
int index = username.indexOf("@");
String domain = username.substring(index + 1);
if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
username = username.substring(0, index);
} else {
// Unknown domain. Return authentication failed.
throw new UnauthorizedException();
}
}
String password;
try {
password = getPasswordValue(username);
}
catch (UserNotFoundException unfe) {
throw new UnauthorizedException();
}
String anticipatedDigest = AuthFactory.createDigest(token, password);
if (!digest.equalsIgnoreCase(anticipatedDigest)) {
throw new UnauthorizedException();
}
// Got this far, so the user must be authorized.
createUser(username);
}
@Override
public boolean isPlainSupported() {
// If the auth SQL is defined, plain text authentication is supported.
return (passwordSQL != null);
}
@Override
public boolean isDigestSupported() {
// The auth SQL must be defined and the password type is supported.
return (passwordSQL != null && passwordTypes.size() == 1 && passwordTypes.get(0) == PasswordType.plain);
}
@Override @Override
public String getPassword(String username) throws UserNotFoundException, public String getPassword(String username) throws UserNotFoundException,
......
...@@ -182,23 +182,6 @@ public class NativeAuthProvider implements AuthProvider { ...@@ -182,23 +182,6 @@ public class NativeAuthProvider implements AuthProvider {
} }
} }
@Override
public void authenticate(String username, String token, String digest)
throws UnauthorizedException
{
throw new UnsupportedOperationException();
}
@Override
public boolean isPlainSupported() {
return true;
}
@Override
public boolean isDigestSupported() {
return false;
}
@Override @Override
public String getPassword(String username) public String getPassword(String username)
throws UserNotFoundException, UnsupportedOperationException throws UserNotFoundException, UnsupportedOperationException
......
...@@ -219,23 +219,6 @@ public class POP3AuthProvider implements AuthProvider { ...@@ -219,23 +219,6 @@ public class POP3AuthProvider implements AuthProvider {
} }
} }
@Override
public void authenticate(String username, String token, String digest)
throws UnauthorizedException
{
throw new UnauthorizedException("Digest authentication not supported.");
}
@Override
public boolean isPlainSupported() {
return true;
}
@Override
public boolean isDigestSupported() {
return false;
}
@Override @Override
public String getPassword(String username) public String getPassword(String username)
throws UserNotFoundException, UnsupportedOperationException throws UserNotFoundException, UnsupportedOperationException
......
...@@ -43,16 +43,6 @@ public class CrowdAuthProvider implements AuthProvider { ...@@ -43,16 +43,6 @@ public class CrowdAuthProvider implements AuthProvider {
} }
} }
@Override
public boolean isPlainSupported() {
return true;
}
@Override
public boolean isDigestSupported() {
return false;
}
/** /**
* Returns if the username and password are valid; otherwise this * Returns if the username and password are valid; otherwise this
* method throws an UnauthorizedException.<p> * method throws an UnauthorizedException.<p>
...@@ -96,11 +86,6 @@ public class CrowdAuthProvider implements AuthProvider { ...@@ -96,11 +86,6 @@ public class CrowdAuthProvider implements AuthProvider {
} }
} }
@Override
public void authenticate(String username, String token, String digest) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {
throw new UnsupportedOperationException("XMPP digest authentication not supported by this version of authentication provider");
}
@Override @Override
public String getPassword(String username) throws UserNotFoundException, UnsupportedOperationException { public String getPassword(String username) throws UserNotFoundException, UnsupportedOperationException {
throw new UnsupportedOperationException("Retrieve password not supported by this version of authentication provider"); throw new UnsupportedOperationException("Retrieve password not supported by this version of authentication provider");
......
...@@ -71,16 +71,6 @@ public class LdapAuthProvider implements AuthProvider { ...@@ -71,16 +71,6 @@ public class LdapAuthProvider implements AuthProvider {
} }
} }
@Override
public boolean isPlainSupported() {
return true;
}
@Override
public boolean isDigestSupported() {
return false;
}
@Override @Override
public void authenticate(String username, String password) throws UnauthorizedException { public void authenticate(String username, String password) throws UnauthorizedException {
if (username == null || password == null || "".equals(password.trim())) { if (username == null || password == null || "".equals(password.trim())) {
...@@ -146,11 +136,6 @@ public class LdapAuthProvider implements AuthProvider { ...@@ -146,11 +136,6 @@ public class LdapAuthProvider implements AuthProvider {
} }
} }
@Override
public void authenticate(String username, String token, String digest) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Digest authentication not currently supported.");
}
@Override @Override
public String getPassword(String username) throws UserNotFoundException, public String getPassword(String username) throws UserNotFoundException,
UnsupportedOperationException UnsupportedOperationException
......
...@@ -127,7 +127,7 @@ public class SASLAuthentication { ...@@ -127,7 +127,7 @@ public class SASLAuthentication {
/** /**
* SASL negotiation has been successful. * SASL negotiation has been successful.
*/ */
authenticated; authenticated
} }
/** /**
...@@ -230,7 +230,7 @@ public class SASLAuthentication { ...@@ -230,7 +230,7 @@ public class SASLAuthentication {
// Construct the configuration properties // Construct the configuration properties
final Map<String, Object> props = new HashMap<>(); final Map<String, Object> props = new HashMap<>();
props.put( LocalClientSession.class.getCanonicalName(), session ); props.put( LocalClientSession.class.getCanonicalName(), session );
props.put( Sasl.POLICY_NOANONYMOUS, Boolean.toString( !XMPPServer.getInstance().getIQAuthHandler().isAnonymousAllowed() ) ); props.put( Sasl.POLICY_NOANONYMOUS, Boolean.toString( !JiveGlobals.getBooleanProperty( "xmpp.auth.anonymous" ) ) );
SaslServer saslServer = Sasl.createSaslServer( mechanismName, "xmpp", session.getServerName(), props, new XMPPCallbackHandler() ); SaslServer saslServer = Sasl.createSaslServer( mechanismName, "xmpp", session.getServerName(), props, new XMPPCallbackHandler() );
if ( saslServer == null ) if ( saslServer == null )
...@@ -437,7 +437,7 @@ public class SASLAuthentication { ...@@ -437,7 +437,7 @@ public class SASLAuthentication {
* mechanism by Openfire. Actual SASL handling is done by Java itself, so you must add * mechanism by Openfire. Actual SASL handling is done by Java itself, so you must add
* the provider to Java. * the provider to Java.
* *
* @param mechanism the name of the new SASL mechanism (cannot be null or an empty String). * @param mechanismName the name of the new SASL mechanism (cannot be null or an empty String).
*/ */
public static void addSupportedMechanism(String mechanismName) { public static void addSupportedMechanism(String mechanismName) {
if ( mechanismName == null || mechanismName.isEmpty() ) { if ( mechanismName == null || mechanismName.isEmpty() ) {
...@@ -490,7 +490,7 @@ public class SASLAuthentication { ...@@ -490,7 +490,7 @@ public class SASLAuthentication {
} }
else if (mech.equals("ANONYMOUS")) { else if (mech.equals("ANONYMOUS")) {
// Check anonymous is supported // Check anonymous is supported
if (!XMPPServer.getInstance().getIQAuthHandler().isAnonymousAllowed()) { if (!JiveGlobals.getBooleanProperty( "xmpp.auth.anonymous" )) {
it.remove(); it.remove();
} }
} }
......
...@@ -3,6 +3,7 @@ package org.jivesoftware.openfire.sasl; ...@@ -3,6 +3,7 @@ package org.jivesoftware.openfire.sasl;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.session.LocalClientSession; import org.jivesoftware.openfire.session.LocalClientSession;
import org.jivesoftware.openfire.session.LocalSession; import org.jivesoftware.openfire.session.LocalSession;
import org.jivesoftware.util.JiveGlobals;
import javax.security.sasl.Sasl; import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException; import javax.security.sasl.SaslException;
...@@ -45,7 +46,7 @@ public class AnonymousSaslServer implements SaslServer ...@@ -45,7 +46,7 @@ public class AnonymousSaslServer implements SaslServer
complete = true; complete = true;
// Verify server-wide policy. // Verify server-wide policy.
if ( !XMPPServer.getInstance().getIQAuthHandler().isAnonymousAllowed() ) if ( !JiveGlobals.getBooleanProperty( "xmpp.auth.anonymous" ) )
{ {
throw new SaslException( "Authentication failed" ); throw new SaslException( "Authentication failed" );
} }
......
...@@ -40,6 +40,7 @@ import org.jivesoftware.openfire.auth.ConnectionException; ...@@ -40,6 +40,7 @@ import org.jivesoftware.openfire.auth.ConnectionException;
import org.jivesoftware.openfire.auth.InternalUnauthenticatedException; import org.jivesoftware.openfire.auth.InternalUnauthenticatedException;
import org.jivesoftware.openfire.auth.UnauthorizedException; import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.event.SessionEventDispatcher; import org.jivesoftware.openfire.event.SessionEventDispatcher;
import org.jivesoftware.openfire.lockout.LockOutManager;
import org.jivesoftware.openfire.session.ClientSession; import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.LocalClientSession; import org.jivesoftware.openfire.session.LocalClientSession;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
...@@ -94,10 +95,8 @@ public class IQAuthHandler extends IQHandler { ...@@ -94,10 +95,8 @@ public class IQAuthHandler extends IQHandler {
probeResponse = DocumentHelper.createElement(QName.get("query", "jabber:iq:auth")); probeResponse = DocumentHelper.createElement(QName.get("query", "jabber:iq:auth"));
probeResponse.addElement("username"); probeResponse.addElement("username");
if (AuthFactory.isPlainSupported()) { if (AuthFactory.supportsPasswordRetrieval()) {
probeResponse.addElement("password"); probeResponse.addElement("password");
}
if (AuthFactory.isDigestSupported()) {
probeResponse.addElement("digest"); probeResponse.addElement("digest");
} }
probeResponse.addElement("resource"); probeResponse.addElement("resource");
...@@ -250,12 +249,12 @@ public class IQAuthHandler extends IQHandler { ...@@ -250,12 +249,12 @@ public class IQAuthHandler extends IQHandler {
username = username.toLowerCase(); username = username.toLowerCase();
// Verify that supplied username and password are correct (i.e. user authentication was successful) // Verify that supplied username and password are correct (i.e. user authentication was successful)
AuthToken token = null; AuthToken token = null;
if (password != null && AuthFactory.isPlainSupported()) { if ( AuthFactory.supportsPasswordRetrieval() ) {
token = AuthFactory.authenticate(username, password); if ( password != null) {
} token = AuthFactory.authenticate( username, password );
else if (digest != null && AuthFactory.isDigestSupported()) { } else if ( digest != null) {
token = AuthFactory.authenticate(username, session.getStreamID().toString(), token = authenticate(username, session.getStreamID().toString(), digest );
digest); }
} }
if (token == null) { if (token == null) {
throw new UnauthorizedException(); throw new UnauthorizedException();
...@@ -361,4 +360,54 @@ public class IQAuthHandler extends IQHandler { ...@@ -361,4 +360,54 @@ public class IQAuthHandler extends IQHandler {
public IQHandlerInfo getInfo() { public IQHandlerInfo getInfo() {
return info; return info;
} }
/**
* Authenticates a user with a username, token, and digest and returns an AuthToken.
* The digest should be generated using the {@link AuthFactory#createDigest(String, String)} method.
* If the username and digest do not match the record of any user in the system, the
* method throws an UnauthorizedException.
*
* @param username the username.
* @param token the token that was used with plain-text password to generate the digest.
* @param digest the digest generated from plain-text password and unique token.
* @return an AuthToken token if the username and digest are correct for the user's
* password and given token.
* @throws UnauthorizedException if the username and password do not match any
* existing user or the account is locked out.
*/
public static AuthToken authenticate(String username, String token, String digest)
throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException {
if (username == null || token == null || digest == null) {
throw new UnauthorizedException();
}
if ( LockOutManager.getInstance().isAccountDisabled(username)) {
LockOutManager.getInstance().recordFailedLogin(username);
throw new UnauthorizedException();
}
username = username.trim().toLowerCase();
if (username.contains("@")) {
// Check that the specified domain matches the server's domain
int index = username.indexOf("@");
String domain = username.substring(index + 1);
if (domain.equals( XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
username = username.substring(0, index);
} else {
// Unknown domain. Return authentication failed.
throw new UnauthorizedException();
}
}
try {
String password = AuthFactory.getPassword( username );
String anticipatedDigest = AuthFactory.createDigest(token, password);
if (!digest.equalsIgnoreCase(anticipatedDigest)) {
throw new UnauthorizedException();
}
}
catch (UserNotFoundException unfe) {
throw new UnauthorizedException();
}
// Got this far, so the user must be authorized.
return new AuthToken(username);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment