package org.jboss.resteasy.keystone.as7;
import org.apache.catalina.connector.Request;
import org.jboss.resteasy.keystone.as7.i18n.LogMessages;
import org.jboss.resteasy.keystone.as7.i18n.Messages;
import org.jboss.resteasy.keystone.core.UserPrincipal;
import org.jboss.resteasy.keystone.model.Access;
import org.jboss.resteasy.keystone.model.Role;
import org.jboss.resteasy.security.smime.PKCS7SignatureInput;
import org.jboss.security.JSSESecurityDomain;
import org.jboss.security.SecurityConstants;
import org.jboss.security.SecurityDomain;
import org.jboss.security.SecurityUtil;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.Principal;
import java.security.acl.Group;
import java.security.cert.X509Certificate;
import java.util.Map;
/**
* Keystone Access token protocol
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SignedSkeletonKeyStoneLoginModule extends JBossWebAuthLoginModule
{
private static final String SECURITY_DOMAIN = "securityDomain";
protected String projectId;
protected String skeletonKeyCertificateAlias;
protected Access access;
/** The SecurityDomain to obtain the KeyStore/TrustStore from */
private Object domain = null;
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options)
{
super.initialize(subject, callbackHandler, sharedState, options);
projectId = (String) options.get("projectId");
skeletonKeyCertificateAlias = (String)options.get("skeleton.key.certificate.alias");
// Get the security domain and default to "other"
String sd = (String) options.get(SECURITY_DOMAIN);
LogMessages.LOGGER.error(Messages.MESSAGES.securityDomain(sd));
sd = SecurityUtil.unprefixSecurityDomain(sd);
if (sd == null)
sd = "other";
try
{
Object tempDomain = new InitialContext().lookup(SecurityConstants.JAAS_CONTEXT_ROOT + sd);
if (tempDomain instanceof SecurityDomain)
{
domain = tempDomain;
}
else {
tempDomain = new InitialContext().lookup(SecurityConstants.JAAS_CONTEXT_ROOT + sd + "/jsse");
if (tempDomain instanceof JSSESecurityDomain) {
domain = tempDomain;
}
else
{
LogMessages.LOGGER.error(Messages.MESSAGES.securityDomainNotValid(sd));
}
}
}
catch (NamingException e)
{
LogMessages.LOGGER.error(Messages.MESSAGES.unableToFindSecurityDomain(sd), e);
}
}
@SuppressWarnings(value = "unchecked")
@Override
protected boolean login(Request request, HttpServletResponse response) throws LoginException
{
String tokenHeader = request.getHeader("X-Auth-Signed-Token");
if (tokenHeader == null) return false; // throw new LoginException("No X-Auth-Signed-Token");
// if we don't have a trust store, we'll just use the key store.
KeyStore keyStore = null;
if( domain != null )
{
if (domain instanceof SecurityDomain)
{
keyStore = ((SecurityDomain) domain).getKeyStore();
}
else
if (domain instanceof JSSESecurityDomain)
{
keyStore = ((JSSESecurityDomain) domain).getKeyStore();
}
}
if (keyStore == null) throw new LoginException(Messages.MESSAGES.noTrustStoreFound());
X509Certificate certificate = null;
try
{
certificate = (X509Certificate)keyStore.getCertificate(skeletonKeyCertificateAlias);
}
catch (KeyStoreException e)
{
throw new LoginException(Messages.MESSAGES.couldNotGetCertificate());
}
try
{
PKCS7SignatureInput input = new PKCS7SignatureInput(tokenHeader);
if (input.verify(certificate) == false) throw new LoginException(Messages.MESSAGES.badSignature());
access = (Access)input.getEntity(Access.class, MediaType.APPLICATION_JSON_TYPE);
}
catch (LoginException le)
{
throw le;
}
catch (Exception e)
{
throw new LoginException(Messages.MESSAGES.badToken());
}
if (access.getToken().expired())
{
throw new LoginException(Messages.MESSAGES.tokenExpired());
}
if (!projectId.equals(access.getToken().getProject().getId()))
{
throw new LoginException(Messages.MESSAGES.tokenProjectIdDoesntMatch());
}
this.loginOk = true;
return true;
}
@Override
protected Principal getIdentity()
{
Principal principal = new UserPrincipal(access.getUser());
return principal;
}
@Override
protected Group[] getRoleSets() throws LoginException
{
SimpleGroup roles = new SimpleGroup("Roles");
Group[] roleSets = {roles};
for (Role role : access.getUser().getRoles())
{
roles.addMember(new SimplePrincipal(role.getName()));
}
return roleSets;
}
}