package org.limewire.friend.impl; import org.apache.http.auth.Credentials; import org.limewire.friend.api.feature.AuthToken; import org.limewire.friend.impl.feature.AuthTokenImpl; import org.limewire.friend.impl.feature.AuthTokenRegistry; import org.limewire.http.auth.Authenticator; import org.limewire.http.auth.AuthenticatorRegistry; import org.limewire.logging.Log; import org.limewire.logging.LogFactory; import org.limewire.security.SHA1; import org.limewire.security.SecurityUtils; import org.limewire.util.StringUtils; import com.google.inject.Inject; import com.google.inject.Singleton; /** * Handles authentication and creation of user passwords for the friend component. * * The class is inherently stateless except for a per session random seed. */ @Singleton class DefaultFriendAuthenticator implements Authenticator, AuthTokenRegistry { private final static Log LOG = LogFactory.getLog(DefaultFriendAuthenticator.class); /** * Per session random seed. */ private final byte[] seed = new byte[SHA1.HASH_LENGTH]; { SecurityUtils.createSecureRandomNoBlock().nextBytes(seed); } @Override @Inject public void register(AuthenticatorRegistry registry) { registry.register(this); } /** * Returns auth token for <code>userId</code>. */ public AuthToken getAuthToken(String userId) { SHA1 sha1 = new SHA1(); byte[] hash = sha1.digest(StringUtils.toUTF8Bytes(userId)); for (int i = 0; i < hash.length; i++) { hash[i] = (byte)(hash[i] ^ seed[i]); } sha1.reset(); // digest again, to make the seed irreconstructible return new AuthTokenImpl(sha1.digest(hash)); } @Override public boolean authenticate(Credentials credentials) { // password can be null String password = credentials.getPassword(); if (password == null) { return false; } AuthToken received = new AuthTokenImpl(password); AuthToken local = getAuthToken(credentials.getUserPrincipal().getName()); if (!received.equals(local)) { if (LOG.isDebugEnabled()) { LOG.debugf("passwords did not match: {0}", password); LOG.debugf("received: {0}, local: {1}", received, local); } return false; } return true; } }