/*
* RealmGuard.java
*
* Created on September 18, 2007, 2:55 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.atomojo.www.util;
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.UUID;
import java.util.logging.Level;
import org.atomojo.app.client.XMLRepresentationParser;
import org.infoset.xml.Document;
import org.infoset.xml.Element;
import org.infoset.xml.XMLException;
import org.restlet.Client;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Cookie;
import org.restlet.data.Method;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.security.ChallengeAuthenticator;
import org.restlet.security.Verifier;
/**
*
* @author alex
*/
public class RealmGuard extends ChallengeAuthenticator
{
Set<UUID> roles;
Reference service;
boolean allowSessions;
boolean allowAuthentication;
/** Creates a new instance of RealmGuard */
public RealmGuard(Context context,ChallengeScheme scheme,String realm,Reference service)
{
super(context,scheme,realm);
this.service = service;
this.roles = new TreeSet<UUID>();
this.allowSessions = false;
this.allowAuthentication = true;
getLogger().info("Using auth service "+service);
setVerifier(new Verifier() {
public int verify(Request request,Response reponse) {
if (allowAuthentication) {
ChallengeResponse cr = request.getChallengeResponse();
if (cr != null) {
String identifier = cr.getIdentifier();
char[] secret = cr.getSecret();
// Check the credentials
if ((identifier != null) && (secret != null)) {
if (checkPassword(request,identifier, secret)) {
return authorize(request) ? Verifier.RESULT_VALID : Verifier.RESULT_INVALID;
} else {
return Verifier.RESULT_INVALID;
}
}
}
}
if (allowSessions) {
Cookie cookie = request.getCookies().getFirst("I");
if (cookie!=null) {
try {
Identity identity = checkSession(getContext().createChildContext(),RealmGuard.this.service,cookie.getValue());
if (identity!=null) {
request.getAttributes().put(Identity.IDENTITY_ATTR,identity);
return Verifier.RESULT_VALID;
}
} catch (RequestFailedException ex) {
if (ex.getStatus()!=null) {
getLogger().severe("Cannot authenticate against service, status="+ex.getStatus().getCode());
} else {
getLogger().log(Level.SEVERE,"Cannot authenticate against service.",ex);
}
}
}
}
return Verifier.RESULT_MISSING;
}
});
}
public void setAllowSessions(boolean flag)
{
allowSessions = flag;
}
public void setAllowAuthentication(boolean flag)
{
allowAuthentication = flag;
}
public Set<UUID> getRoles() {
return roles;
}
public static Identity checkSession(Context context,Reference service,String session)
throws RequestFailedException
{
Client client = context.getClientDispatcher();
//Client client = new Client(context,service.getSchemeProtocol());
//client.getContext().getAttributes().put("hostnameVerifier", org.apache.commons.ssl.HostnameVerifier.DEFAULT);
Reference ref = new Reference(service+"/"+session);
Request authRequest = new Request(Method.GET,ref);
Response response = client.handle(authRequest);
try {
if (response.getStatus().isSuccess()) {
try {
return createIdentity(response.getEntity());
} catch (Exception ex) {
throw new RequestFailedException("Exception while processing result from session lookup.",ex);
}
} else if (response.getStatus().getCode()==Status.CLIENT_ERROR_UNAUTHORIZED.getCode()) {
return null;
} else {
throw new RequestFailedException("Request to realm failed.",response.getStatus());
}
} finally {
if (response.isEntityAvailable()) {
response.getEntity().release();
}
}
}
public static Identity createIdentity(Representation entity)
throws IOException,XMLException
{
XMLRepresentationParser parser = new XMLRepresentationParser();
Document doc = parser.load(entity);
String session = doc.getDocumentElement().getAttributeValue("id");
String id = doc.getDocumentElement().getAttributeValue("user-id");
String alias = doc.getDocumentElement().getAttributeValue("user-alias");
Element nameE = doc.getDocumentElement().getFirstElementNamed(IdentityFilter.NAME);
Element emailE = doc.getDocumentElement().getFirstElementNamed(IdentityFilter.EMAIL);
Identity identity = new Identity(session,id,alias,nameE==null ? null : nameE.getText(),emailE==null ? null : emailE.getText());
Iterator<Element> roles = doc.getDocumentElement().getElementsByName(IdentityFilter.ROLE);
while (roles.hasNext()) {
Element role = roles.next();
UUID rid = UUID.fromString(role.getAttributeValue("id"));
String name = role.getAttributeValue("name");
if (identity.roles==null) {
identity.roles = new TreeMap<UUID,String>();
}
identity.roles.put(rid,name);
}
Iterator<Element> groups = doc.getDocumentElement().getElementsByName(IdentityFilter.GROUP);
while (groups.hasNext()) {
Element group = groups.next();
UUID gid = UUID.fromString(group.getAttributeValue("id"));
String galias = group.getAttributeValue("alias");
if (identity.groups==null) {
identity.groups = new TreeMap<UUID,String>();
}
identity.groups.put(gid,galias);
}
return identity;
}
public static Identity authenticateAgainstService(Context context,Reference service,String username,String password)
throws RequestFailedException
{
Client client = new Client(context,service.getSchemeProtocol());
client.getContext().getAttributes().put("hostnameVerifier", org.apache.commons.ssl.HostnameVerifier.DEFAULT);
Request authRequest = new Request(Method.GET,service);
authRequest.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_BASIC,username,password));
Response response = client.handle(authRequest);
if (response.getStatus().isSuccess()) {
try {
return createIdentity(response.getEntity());
} catch (Exception ex) {
throw new RequestFailedException("Exception while processing result from authentication.",ex);
}
} else if (response.getStatus().getCode()==Status.CLIENT_ERROR_UNAUTHORIZED.getCode()) {
return null;
} else {
throw new RequestFailedException("Request to realm failed.",response.getStatus());
}
}
public boolean checkPassword(Request request,String identifier,char [] secret)
{
getLogger().info("Checking authentication for "+identifier);
try {
Identity identity = authenticateAgainstService(getContext().createChildContext(),service,identifier,new String(secret));
if (identity==null) {
return false;
} else {
request.getAttributes().put(Identity.IDENTITY_ATTR,identity);
return true;
}
} catch (RequestFailedException ex) {
if (ex.getStatus()!=null) {
getLogger().severe("Cannot authenticate against service, status="+ex.getStatus().getCode());
} else {
getLogger().log(Level.SEVERE,"Cannot authenticate against service.",ex);
}
return false;
}
}
public boolean authorize(Request request) {
if (roles.size()>0) {
Identity identity = (Identity)request.getAttributes().get(Identity.IDENTITY_ATTR);
for (UUID role : roles) {
if (!identity.hasRole(role)) {
getLogger().info(identity.getAlias()+" not authorized, missing role "+role);
request.getAttributes().remove(Identity.IDENTITY_ATTR);
return false;
}
}
return true;
} else {
return true;
}
}
}