/*
* SyncResource.java
*
* Created on April 12, 2007, 1:39 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.atomojo.auth.service.app;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import org.atomojo.app.client.XMLEntity;
import org.atomojo.auth.service.db.AuthDB;
import org.atomojo.auth.service.db.Group;
import org.atomojo.auth.service.db.Permission;
import org.atomojo.auth.service.db.Realm;
import org.atomojo.auth.service.db.RealmUser;
import org.atomojo.auth.service.db.Role;
import org.atomojo.auth.service.db.User;
import org.atomojo.auth.service.db.XML;
import org.restlet.Request;
import org.restlet.data.ChallengeRequest;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ServerResource;
/**
*
* @author alex
*/
public class AuthResource extends ServerResource
{
long expiration = 3600*1000;
AuthDB db;
Realm realm;
boolean realmRequired;
/** Creates a new instance of SyncResource */
public AuthResource() {
setNegotiated(false);
}
protected void doInit() {
db = (AuthDB)getRequest().getAttributes().get(AuthApplication.DB_ATTR);
realm = (Realm)getRequest().getAttributes().get(AuthApplication.REALM_ATTR);
Boolean checkRealm = (Boolean)getRequest().getAttributes().get(AuthApplication.REALM_REQUIRED_ATTR);
realmRequired = checkRealm==null ? false : checkRealm.booleanValue();
}
static User findUser(AuthDB db,String authid)
throws SQLException,IllegalArgumentException
{
User user = null;
if (authid.startsWith("urn:uuid:")) {
// by uuid
UUID userid = UUID.fromString(authid.substring(9));
user = db.getUser(userid);
} else if (authid.indexOf('@')>0) {
// by e-mail
user = db.findUserByEmail(authid);
} else {
// by alias
user = db.getUser(authid);
}
return user;
}
static RealmUser findRealmUser(AuthDB db,Realm realm,String authid)
throws SQLException,IllegalArgumentException
{
RealmUser user = null;
if (authid.startsWith("urn:uuid:")) {
// by uuid
UUID userid = UUID.fromString(authid.substring(9));
user = db.getRealmUser(realm,userid);
} else if (authid.indexOf('@')>0) {
// by e-mail
user = db.findRealmUserByEmail(realm,authid);
} else {
// by alias
user = db.getRealmUser(realm,authid);
}
return user;
}
Representation getSessionEntity(UUID session,UUID userId,String userAlias,String name,String email,Iterator<Role> roles,Iterator<Group> groups)
{
Set<Role> userRoles = new HashSet<Role>();
if (roles!=null) {
while (roles.hasNext()) {
userRoles.add(roles.next());
}
}
StringBuilder groupsRep = new StringBuilder();
if (groups!=null) {
while (groups.hasNext()) {
Group group = groups.next();
groupsRep.append("<group id='"+group.getUUID()+"' alias='"+group.getAlias()+"'/>\n");
Iterator<Role> groupRoles = group.getRoles();
while (groupRoles!=null && groupRoles.hasNext()) {
userRoles.add(groupRoles.next());
}
}
}
StringBuilder rolesRep = new StringBuilder();
for (Role role : userRoles) {
rolesRep.append("<role id='"+role.getUUID()+"' name='"+role.getName()+"'/>\n");
}
return new StringRepresentation(
"<session xmlns='"+XML.authNS+"' "+(session==null ? "" : "id='"+session+"' ")+"user-id='"+userId+"'"+(userAlias==null ? "" : " user-alias='"+userAlias+"'")+">\n" +
(name==null ? "" : "<name>"+XMLEntity.escape(name)+"</name>\n") +
(email==null ? "" : "<email>"+XMLEntity.escape(email)+"</email>\n") +
groupsRep.toString() +
rolesRep.toString() +
"</session>",
MediaType.APPLICATION_XML
);
}
public Representation get()
{
if (realmRequired && realm==null) {
getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
return null;
}
Form requestForm = getRequest().getResourceRef().getQueryAsForm();
//getContext().getLogger().info("Testing auth...");
try {
ChallengeResponse authorization = getRequest().getChallengeResponse();
String idValue = AuthApplication.getStringAttribute(getRequest(),"session",null);
if (authorization==null || idValue!=null) {
if (idValue!=null) {
try {
UUID id = UUID.fromString(idValue);
User.Authenticated authd = db.isAuthenticated(realm,id);
if (authd!=null) {
String userAlias = authd.getUser().getAlias();
UUID userId = authd.getUser().getUUID();
String name = authd.getUser().getName();
String email = authd.getUser().getEmail();
Iterator<Group> groups = null;
Iterator<Role> roles = authd.getUser().getRoles();
// If we have a realm, we need the realm user to get the right alias
if (realm!=null) {
RealmUser ruser = db.findRealmUser(realm,authd.getUser());
if (ruser!=null) {
userAlias = ruser.getAlias();
name = ruser.getName();
email = ruser.getEmail();
groups = ruser.getGroups();
}
}
getResponse().setStatus(Status.SUCCESS_OK);
return getSessionEntity(authd.getSession(),userId,userAlias,name,email,roles,groups);
}
} catch (IllegalArgumentException ex) {
getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
return null;
}
}
getResponse().setChallengeRequests(Collections.singletonList(new ChallengeRequest(ChallengeScheme.HTTP_BASIC,realm==null ? "users" : "realm "+realm.getName())));
getResponse().setStatus(Status.CLIENT_ERROR_UNAUTHORIZED);
return null;
}
String authid = authorization.getIdentifier().trim();
String password = new String(authorization.getSecret());
User user = null;
if (realm!=null) {
RealmUser ruser = findRealmUser(db,realm,authid);
if (ruser!=null) {
user = ruser.getUser();
}
if (user==null) {
// see if the user is a super user across realms
user = findUser(db,authid);
if (user!=null) {
// The user must either be a superuser or have the cross-realm permission
Permission superuser = db.getPermission(AuthDB.SUPERUSER_PERMISSION);
Permission crossrealm = db.getPermission(AuthDB.ACROSS_REALM_PERMISSION);
if (!user.hasPermission(superuser) && !user.hasPermission(crossrealm)) {
user = null;
}
}
}
} else {
user = findUser(db,authid);
}
if (user!=null) {
try {
String seconds = requestForm.getFirstValue("expiration");
long requestExpiration = seconds==null ? expiration : Long.parseLong(seconds)*1000;
if ("false".equals(requestForm.getFirstValue("session"))) {
requestExpiration = 0;
}
User.Authenticated authd = user.authenticate(realm,password,requestExpiration);
if (authd!=null) {
String userAlias = authd.getUser().getAlias();
UUID userId = authd.getUser().getUUID();
String name = authd.getUser().getName();
String email = authd.getUser().getEmail();
Iterator<Group> groups = null;
Iterator<Role> roles = authd.getUser().getRoles();
// If we have a realm, we need the realm user to get the right alias
if (realm!=null) {
RealmUser ruser = db.findRealmUser(realm,authd.getUser());
if (ruser!=null) {
userAlias = ruser.getAlias();
name = ruser.getName();
email = ruser.getEmail();
groups = ruser.getGroups();
}
}
getResponse().setStatus(Status.SUCCESS_OK);
return getSessionEntity(authd.getSession(),userId,userAlias,name,email,roles,groups);
}
} catch (Exception ex) {
getContext().getLogger().log(Level.SEVERE,"Failed to authenticate due to exception.",ex);
getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
return null;
}
}
getResponse().setStatus(Status.CLIENT_ERROR_UNAUTHORIZED);
getResponse().setChallengeRequests(Collections.singletonList(new ChallengeRequest(ChallengeScheme.HTTP_BASIC,realm==null ? "Realm Users" : "Users")));
} catch (SQLException ex) {
getContext().getLogger().log(Level.SEVERE,"Cannot get user data from database.",ex);
getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
}
return null;
}
public boolean allowDelete() {
return true;
}
public Representation delete() {
String sessionS = AuthApplication.getStringAttribute(getRequest(),"session",null);
if (sessionS==null) {
getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
return null;
}
try {
UUID session = UUID.fromString(sessionS);
db.expireSession(session);
} catch (IllegalArgumentException ex) {
getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
} catch (SQLException ex) {
getContext().getLogger().log(Level.SEVERE,"Cannot delete session "+sessionS+" from database.",ex);
getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
}
return null;
}
}