/* * eXist Open Source Native XML Database * Copyright (C) 2001-2009 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ package org.exist.xquery.functions.xmldb; import org.apache.log4j.Logger; import org.exist.dom.QName; import org.exist.http.servlets.RequestWrapper; import org.exist.http.servlets.SessionWrapper; import org.exist.security.User; import org.exist.xmldb.UserManagementService; import org.exist.xmldb.XmldbURI; import org.exist.xquery.BasicFunction; import org.exist.xquery.Cardinality; import org.exist.xquery.FunctionSignature; import org.exist.xquery.Variable; import org.exist.xquery.XPathException; import org.exist.xquery.XQueryContext; import org.exist.xquery.functions.request.RequestModule; import org.exist.xquery.functions.session.SessionModule; import org.exist.xquery.value.BooleanValue; import org.exist.xquery.value.FunctionReturnSequenceType; import org.exist.xquery.value.FunctionParameterSequenceType; import org.exist.xquery.value.JavaObjectValue; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.SequenceType; import org.exist.xquery.value.Type; import org.xmldb.api.DatabaseManager; import org.xmldb.api.base.Collection; import org.xmldb.api.base.XMLDBException; /** * @author Wolfgang Meier (wolfgang@exist-db.org) * @author Andrzej Taramina (andrzej@chaeron.com) * @author ljo */ public class XMLDBAuthenticate extends BasicFunction { private static final Logger logger = Logger.getLogger(XMLDBAuthenticate.class); public final static FunctionSignature authenticateSignature = new FunctionSignature( new QName("authenticate", XMLDBModule.NAMESPACE_URI, XMLDBModule.PREFIX), "Check if the user, $user-id, can authenticate against the database collection $collection-uri. The function simply tries to " + "read the collection $collection-uri, using the credentials " + "$user-id and $password. " + "It returns true if the authentication succeeds, false otherwise.", new SequenceType[] { new FunctionParameterSequenceType("collection-uri", Type.STRING, Cardinality.EXACTLY_ONE, "The collection URI"), new FunctionParameterSequenceType("user-id", Type.STRING, Cardinality.ZERO_OR_ONE, "The user-id"), new FunctionParameterSequenceType("password", Type.STRING, Cardinality.ZERO_OR_ONE, "The password") }, new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE, "true() on successful authentication, false() otherwise") ); public final static FunctionSignature loginSignatures[] = { new FunctionSignature( new QName("login", XMLDBModule.NAMESPACE_URI, XMLDBModule.PREFIX), "Login the user, $user-id, and set it as the owner " + "of the currently executing XQuery. " + "It returns true if the authentication succeeds, false otherwise. " + "If called from a HTTP context the login is cached for the " + "lifetime of the HTTP session and may be used for any XQuery " + "run in that session. " + "If an HTTP session does not already exist, none will be created.", new SequenceType[] { new FunctionParameterSequenceType("collection-uri", Type.STRING, Cardinality.EXACTLY_ONE, "The collection URI"), new FunctionParameterSequenceType("user-id", Type.STRING, Cardinality.ZERO_OR_ONE, "The user-id"), new FunctionParameterSequenceType("password", Type.STRING, Cardinality.ZERO_OR_ONE, "The password") }, new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE, "true() on successful authentication and owner elevation, false() otherwise") ), new FunctionSignature( new QName("login", XMLDBModule.NAMESPACE_URI, XMLDBModule.PREFIX), "Login the user, $user-id, and set it as the owner " + "of the currently executing XQuery. " + "It returns true() if the authentication succeeds, " + "false() otherwise. " + "If called from a HTTP context the login is cached for the " + "lifetime of the HTTP session and may be used for any XQuery" + "run in that session. " + "$create-session specifies whether to create an HTTP session on " + "successful authentication or not. " + "If $create-session is false() or the empty sequence no session " + "will be created if one does not already exist.", new SequenceType[] { new FunctionParameterSequenceType("collection-uri", Type.STRING, Cardinality.EXACTLY_ONE, "The collection URI"), new FunctionParameterSequenceType("user-id", Type.STRING, Cardinality.ZERO_OR_ONE, "The user-id"), new FunctionParameterSequenceType("password", Type.STRING, Cardinality.ZERO_OR_ONE, "The password"), new FunctionParameterSequenceType("create-session", Type.BOOLEAN, Cardinality.ZERO_OR_ONE, "whether to create the session or not on successful authentication, default false()") }, new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE, "true() on successful authentication and owner elevation, false() otherwise") ) }; /** * @param context * @param signature */ public XMLDBAuthenticate( XQueryContext context, FunctionSignature signature ) { super( context, signature ); } /* (non-Javadoc) * @see org.exist.xquery.BasicFunction#eval(org.exist.xquery.value.Sequence[], org.exist.xquery.value.Sequence) */ public Sequence eval( Sequence[] args, Sequence contextSequence ) throws XPathException { if( args[1].isEmpty() ) { return BooleanValue.FALSE; } String uri = args[0].getStringValue(); String userName = args[1].getStringValue(); String password = args[2].getStringValue(); boolean createSession = false; if (args.length > 3) { createSession = args[3].effectiveBooleanValue(); } XmldbURI targetColl; if( !uri.startsWith( XmldbURI.XMLDB_SCHEME + ':' ) ) { targetColl = XmldbURI.EMBEDDED_SERVER_URI.resolveCollectionPath( XmldbURI.create( uri ) ); } else { targetColl = XmldbURI.create( uri ); } try { Collection root = DatabaseManager.getCollection( targetColl.toString(), userName, password ); if( root == null ) { logger.error("Unable to authenticate user: target collection " + targetColl + " does not exist"); throw( new XPathException( this, "Unable to authenticate user: target collection " + targetColl + " does not exist" ) ); } if( isCalledAs( "login" ) ) { UserManagementService ums = (UserManagementService)root.getService( "UserManagementService", "1.0" ); User user = ums.getUser( userName ); context.getBroker().setUser( user ); /** if there is a http session cache the user in the http session */ cacheUserInHttpSession( user, createSession ); } return BooleanValue.TRUE; } catch (XMLDBException e) { return BooleanValue.FALSE; } } /** * If there is a HTTP Session, then this will store the user object in the session under the key * defined by XQueryContext.HTTP_SESSIONVAR_XMLDB_USER * * @param user The User to cache in the session * @param createSession Create session? */ private void cacheUserInHttpSession( User user, boolean createSession ) throws XPathException { Variable var = getSessionVar( createSession ); if( var != null && var.getValue() != null ) { if( var.getValue().getItemType() == Type.JAVA_OBJECT ) { JavaObjectValue session = (JavaObjectValue) var.getValue().itemAt(0); if( session.getObject() instanceof SessionWrapper ) { ((SessionWrapper)session.getObject()).setAttribute( XQueryContext.HTTP_SESSIONVAR_XMLDB_USER, user ); } } } } /** * Get the HTTP Session variable. Create it if requested and it doesn't exist. * * @param createSession Create session? */ private Variable getSessionVar( boolean createSession ) throws XPathException { SessionModule sessionModule = (SessionModule)context.getModule( SessionModule.NAMESPACE_URI ); Variable var = sessionModule.resolveVariable( SessionModule.SESSION_VAR ); if( createSession && ( var == null || var.getValue() == null ) ) { SessionWrapper session = null; RequestModule reqModule = (RequestModule)context.getModule( RequestModule.NAMESPACE_URI ); // request object is read from global variable $request Variable reqVar = reqModule.resolveVariable( RequestModule.REQUEST_VAR ); if( reqVar == null || reqVar.getValue() == null ) { logger.error("No request object found in the current XQuery context."); throw( new XPathException( this, "No request object found in the current XQuery context." ) ); } if( reqVar.getValue().getItemType() != Type.JAVA_OBJECT ) { logger.error( "Variable $request is not bound to an Java object."); throw( new XPathException( this, "Variable $request is not bound to an Java object." ) ); } JavaObjectValue reqValue = (JavaObjectValue)reqVar.getValue().itemAt( 0) ; if( reqValue.getObject() instanceof RequestWrapper ) { session = ((RequestWrapper)reqValue.getObject()).getSession( true ); var = sessionModule.declareVariable( SessionModule.SESSION_VAR, session ); } } return( var ); } }