package edu.gatech.oad.rocket.findmythings.server.security;
import com.google.common.base.Preconditions;
import edu.gatech.oad.rocket.findmythings.server.db.DatabaseService;
import edu.gatech.oad.rocket.findmythings.server.db.MemcacheManager;
import edu.gatech.oad.rocket.findmythings.server.db.model.DBAuthenticationToken;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import java.util.Collection;
import java.util.logging.Logger;
public class BearerTokenAuthenticatingRealm extends AuthenticatingRealm {
private static final Logger LOGGER = Logger.getLogger(BearerTokenAuthenticatingRealm.class.getName());
private class BearerAuthenticationInfo implements AuthenticationInfo {
private static final long serialVersionUID = 3470761774414912759L;
private final DBAuthenticationToken token;
BearerAuthenticationInfo(DBAuthenticationToken token) {
this.token = token;
}
@Override
public Object getCredentials() {
return token.getIdentifierString();
}
@Override
public PrincipalCollection getPrincipals() {
RealmSecurityManager manager = (RealmSecurityManager)SecurityUtils.getSecurityManager();
SimplePrincipalCollection ret = new SimplePrincipalCollection();
for (Realm realm : manager.getRealms()) {
if (realm instanceof ProfileRealm) {
String email = token.getEmail();
if (((ProfileRealm) realm).accountExists(email)) {
ret.add(email, realm.getName());
}
}
}
ret.add(token.getIdentifierString(), getName());
return ret;
}
}
public BearerTokenAuthenticatingRealm() {
super(new MemcacheManager(), new AllowAllCredentialsMatcher());
setAuthenticationTokenClass(BearerToken.class);
}
private static boolean tokenIsInvalid(BearerToken token, DBAuthenticationToken dbToken) {
return token == null || dbToken == null || !dbToken.getEmail().equals(token.getPrincipal());
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
BearerToken token = (BearerToken)arg0;
String email = (String)token.getPrincipal();
String credentials = (String)token.getCredentials();
Preconditions.checkNotNull(email, "Email can't be null");
Preconditions.checkNotNull(token, "Token can't be null");
DBAuthenticationToken dbToken = DatabaseService.ofy().load().type(DBAuthenticationToken.class).id(credentials).get();
if (tokenIsInvalid(token, dbToken)) {
LOGGER.info("Rejecting token " + credentials + " for user " + email);
return null;
}
return new BearerAuthenticationInfo(dbToken);
}
@Override
public void onLogout(PrincipalCollection principals) {
super.onLogout(principals);
deleteTokens(principals);
}
@SuppressWarnings("unchecked")
private void deleteTokens(PrincipalCollection principals) {
Collection<String> tokens = principals.fromRealm(getName());
if (tokens != null) { // && tokens.size() > 1
DatabaseService.ofy().deleteAuthenticationTokens(tokens);
}
}
}