jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r638834 [4/14] - in /jackrabbit/trunk: jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/ jackr...
Date Wed, 19 Mar 2008 13:57:11 GMT
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,643 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.commons.collections.set.ListOrderedSet;
+import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.Impersonation;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.core.config.LoginModuleConfig;
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.principal.PrincipalProvider;
+import org.apache.jackrabbit.core.security.principal.PrincipalProviderRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This Abstract class provides the means for the common Authentication tasks,
+ * within the Repository.<p />
+ * It implements an authentication by User-ID / Password - Credentials
+ * {@link SimpleCredentials}<p />
+ * On successfull authentication it relates this credentials to principals
+ * by the use of * the {@link PrincipalProvider} configured for this LoginModule<p />
+ * Jackrabbit knows about two typs of Login, the one for its "own" Credentials and one
+ * for Impersonation.<br>
+ * {@link #login()}-method dispatches to
+ * {@link #authenticate(java.security.Principal, javax.jcr.Credentials)} and
+ * {@link #impersonate(java.security.Principal, javax.jcr.Credentials)} for the
+ * two cases for implemenations.<br>
+ * This LoginModule imlements default behaviours for this methods.
+ *
+ * @see LoginModule
+ */
+public abstract class AbstractLoginModule implements LoginModule {
+
+    private static final Logger log = LoggerFactory.getLogger(AbstractLoginModule.class);
+
+    private static final String KEY_SIMPLE_CREDENTIALS = "org.apache.jackrabbit.credentials.simple";
+    private static final String KEY_LOGIN_NAME = "javax.security.auth.login.name";
+
+    protected String anonymousId;
+    protected String defaultUserId;
+
+    private CallbackHandler callbackHandler;
+    private boolean initialized;
+
+    protected Principal principal;
+    protected SimpleCredentials credentials;
+    protected Subject subject;
+    protected PrincipalProvider principalProvider;
+
+    private Map sharedState;
+
+    /**
+     * Initialize this LoginModule.<br> This abstract implementation, initalizes
+     * the following fields for later use:
+     * <ul>
+     * <li>{@link PrincipalManager} for group-membership resoultion</li>
+     * <li>{@link PrincipalProvider} for user-{@link Principal} resolution.</li>
+     * <li>{@link LoginModuleConfig#PARAM_DEFAULT_USERID} option is evaluated</li>
+     * <li>{@link LoginModuleConfig#PARAM_ADMIN_ID} option is evaluated</li>
+     * <li>{@link LoginModuleConfig#PARAM_ANONYMOUS_ID} option is evaluated</li>
+     * </ul>
+     * Implementations are called via
+     * {@link #doInit(CallbackHandler, Session, Map)} to implement
+     * additional initalization
+     *
+     * @param subject         the <code>Subject</code> to be authenticated. <p>
+     * @param callbackHandler a <code>CallbackHandler</code> for communicating
+     *                        with the end user (prompting for usernames and
+     *                        passwords, for example). <p>
+     * @param sharedState     state shared with other configured
+     *                        LoginModules.<p>
+     * @param options         options specified in the login <code>Configuration</code>
+     *                        for this particular <code>LoginModule</code>.
+     * @see LoginModule#initialize(Subject, CallbackHandler, Map, Map)
+     * @see #doInit(CallbackHandler, Session, Map)
+     * @see #isInitialized()
+     */
+    public void initialize(Subject subject, CallbackHandler callbackHandler,
+                           Map sharedState, Map options) {
+        try {
+            log.debug("Initalize LoginModule: ");
+            //Properties configProps = new Properties();
+            //configProps.putAll(options);
+            RepositoryCallback repositoryCb = new RepositoryCallback();
+            callbackHandler.handle(new Callback[]{repositoryCb});
+
+            // retrieve the principal-provider configured for this module
+            PrincipalProviderRegistry registry = repositoryCb.getPrincipalProviderRegistry();
+            if (options.containsKey(LoginModuleConfig.PARAM_PRINCIPAL_PROVIDER_CLASS)) {
+                String providerName = (String) options.get(LoginModuleConfig.PARAM_PRINCIPAL_PROVIDER_CLASS);
+                principalProvider = registry.getProvider(providerName);
+            }
+            if (principalProvider == null) {
+                principalProvider = registry.getDefault();
+                if (principalProvider==null) {
+                    return; // abort. not even a default principal provider
+                }
+            }
+            log.debug("- PrincipalProvider -> '" + principalProvider.getClass().getName() + "'");
+
+            //call implementation for additional setup
+            doInit(callbackHandler, repositoryCb.getSession(), options);
+
+            if (options.containsKey(LoginModuleConfig.PARAM_ANONYMOUS_ID)) {
+                anonymousId = (String) options.get(LoginModuleConfig.PARAM_ANONYMOUS_ID);
+            }
+            if (options.containsKey(LoginModuleConfig.PARAM_DEFAULT_USERID)) {
+                defaultUserId = (String) options.get(LoginModuleConfig.PARAM_DEFAULT_USERID);
+            }
+
+            //common jaas state variables
+            this.callbackHandler = callbackHandler;
+            this.subject = subject;
+
+            //log config values for debug
+            if (log.isDebugEnabled()) {
+                Iterator itr = options.keySet().iterator();
+                while (itr.hasNext()) {
+                    String option = (String) itr.next();
+                    log.debug("- Option: "+ option +" -> '"+ options.get(option) +"'");
+
+                }
+            }
+
+            this.sharedState = sharedState;
+            initialized = (this.subject != null);
+
+        } catch (Exception e) {
+            log.error("LoginModule failed to initialize.", e);
+        }
+    }
+
+    /**
+     * Implementations may set-up their own state. E. g. a DataSource if it is
+     * authorized against an external System
+     *
+     * @param callbackHandler as passed by {@link javax.security.auth.login.LoginContext}
+     * @param session         to security-workspace of Jackrabbit
+     * @param options         options from Logini config
+     * @throws LoginException in case initializeaiton failes
+     */
+    protected abstract void doInit(CallbackHandler callbackHandler,
+                                   Session session,
+                                   Map options) throws LoginException;
+
+
+    /**
+     * Returns <code>true</code> if this module has been successfully initialized.
+     *
+     * @return <code>true</code> if this module has been successfully initialized.
+     * @see LoginModule#initialize(Subject, CallbackHandler, Map, Map)
+     */
+    protected boolean isInitialized() {
+        return initialized;
+    }
+
+    /**
+     * Method to authenticate a <code>Subject</code> (phase 1).<p/>
+     * The login is devided into 3 Phases:<p/>
+     *
+     * <b>1) User-ID resolution</b><br>
+     * In a first step it is tried to resolve a User-ID for further validation.
+     * As for JCR the identification is marked with the {@link Credentials}
+     * interface, credentials are accessed in this phase.<br>
+     * If no User-ID can be found, anonymous access is granted with the ID of
+     * the anonymous user (as defined in the security configuration).
+     * Anonymous access can be switched off removing the configuration entry.
+     * <br> This implementation uses two helper-methods, which allow for
+     * customization:
+     * <ul>
+     * <li>{@link #getCredentials()}</li> and
+     * <li>{@link #getUserID(Credentials)}</li>
+     * </ul>
+     * <p/>
+     *
+     * <b>2) User-Principal resolution </b><br>
+     * In a second step it is tested, if the resolved User-ID belongs to a User
+     * known to the system, i.e. if the {@link PrincipalProvider} has a principal
+     * for the given ID and the principal can be found via
+     * {@link PrincipalProvider#findPrincipals(String)}.<br>
+     * The provider implemenation can be set by the configuration option with the
+     * name {@link LoginModuleConfig#PARAM_PRINCIPAL_PROVIDER_CLASS principal_provider.class}.
+     * If the option is missing, the system default prinvipal provider will
+     * be used.<p/>
+     *
+     * <b>3) Verfication</b><br>
+     * There are two cases, how the User-ID can be verfied:
+     * Either the login is the result of an impersonation request (see
+     * {@link javax.jcr.Session#impersonate(Credentials)} or of a login to the Repository ({@link
+     * javax.jcr.Repository#login(Credentials)}). The concrete implementation
+     * of the LoginModule is responsible for both impersonation and login:
+     * <ul>
+     * <li>{@link #authenticate(Principal, Credentials)}</li>
+     * <li>{@link #impersonate(Principal, Credentials)}</li>
+     * </ul>
+     *
+     * Under the following conditions, the login process is aborted and the
+     * module is marked to be ignored:
+     * <ul>
+     * <li>No User-ID could be resolve, and anyonymous access is switched off</li>
+     * <li>No Principal is found for the User-ID resolved</li>
+     * </ul>
+     *
+     * Under the follwoing conditions, the login process is marked to be invalid
+     * by throwing an LoginException:
+     * <ul>
+     * <li>It is an impersonation request, but the impersonator is not allowed
+     * to impersonate to the requested User-ID</li>
+     * <li>The user tries to login, but the Credentials can not be verified.</li>
+     * </ul>
+     * <p/>
+     * The LoginModule keeps the Credentials and the Principal as instance fields,
+     * to mark that login has been successfull.
+     *
+     * @return true if the authentication succeeded, or false if this
+     *         <code>LoginModule</code> should be ignored.
+     * @throws LoginException if the authentication fails
+     * @see LoginModule#login()
+     * @see #getCredentials()
+     * @see #getUserID(Credentials)
+     * @see #getImpersonatorSubject(Credentials)
+     */
+    public boolean login() throws LoginException {
+        if (!isInitialized()) {
+            log.warn("Unable to perform login: initialization not completed.");
+            return false;
+        }
+
+        //check for availablity of Credentials;
+        Credentials creds = getCredentials();
+        if (creds == null) {
+            log.warn("No credentials available -> try default (anonymous) authentication.");
+        }
+        try {
+            Principal userPrincipal = getPrincipal(creds);
+            if (userPrincipal == null) {
+                // unknown principal or a Group-principal
+                log.debug("Unknown User -> ignore.");
+                return false;
+            }
+            boolean authenticated;
+            // test for anonymous, impersonation or common authentication.
+            if (isAnonymous(creds)) {
+                authenticated = true;
+            } else if (isImpersonation(creds)) {
+                authenticated = impersonate(userPrincipal, creds);
+            } else {
+                authenticated = authenticate(userPrincipal, creds);
+            }
+
+            // process authenticated user or return false
+            if (authenticated) {
+                if (creds instanceof SimpleCredentials) {
+                    credentials = (SimpleCredentials) creds;
+                } else {
+                    credentials = new SimpleCredentials(getUserID(creds), new char[0]);
+                }
+                principal = userPrincipal;
+                return true;
+            }
+        } catch (RepositoryException e) {
+            log.error("Login failed:", e);
+        }
+        return false;
+    }
+
+    /**
+     * Method to commit the authentication process (phase 2).
+     * <p/>
+     * <p> This method is called if the LoginContext's overall authentication
+     * succeeded (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL
+     * LoginModules succeeded).
+     * <p/>
+     * <p> If this LoginModule's own authentication attempt succeeded (checked
+     * by retrieving the private state saved by the <code>login</code> method),
+     * then this method associates relevant Principals and Credentials with the
+     * <code>Subject</code> located in the <code>LoginModule</code>.  If this
+     * LoginModule's own authentication attempted failed, then this method
+     * removes/destroys any state that was originally saved.
+     * <p/>
+     * The login is considers as succeeded if the credentials field is set. If
+     * there is no principalstate. the login is considered as ignored.
+     * <p/>
+     * The implementation stores the principal associated to the UserID and all
+     * the Groups it is member of. {@link PrincipalManager#getGroupMembership(Principal)}
+     * An instance of (#link SimpleCredentials} containing only the UserID used
+     * to login is set to the Subject's public Credentials
+     *
+     * @return true if this method succeeded, or false if this
+     *         <code>LoginModule</code> should be ignored.
+     * @throws LoginException if the commit fails
+     * @see LoginModule#commit()
+     * @see AbstractLoginModule#login()
+     */
+    public boolean commit() throws LoginException {
+        //check login-state
+        if (credentials == null) {
+            abort();
+        }
+        if (!isInitialized() || principal == null) {
+            return false;
+        }
+
+        subject.getPrincipals().addAll(getPrincipals());
+        subject.getPublicCredentials().add(credentials);
+        return true;
+    }
+
+    /**
+     * Method to abort the authentication process (phase 2).
+     * <p/>
+     * <p> This method is called if the LoginContext's overall authentication
+     * failed. (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL
+     * LoginModules did not succeed).
+     * <p/>
+     * <p> If this LoginModule's own authentication attempt succeeded (checked
+     * by retrieving the private state saved by the <code>login</code> method),
+     * then this method cleans up any state that was originally saved.
+     * <p/>
+     * <p/>
+     *
+     * @return true if this method succeeded, or false if this
+     *         <code>LoginModule</code> should be ignored.
+     * @throws LoginException if the abort fails
+     */
+    public boolean abort() throws LoginException {
+        if (!isInitialized()) {
+            return false;
+        } else {
+            sharedState.remove(KEY_SIMPLE_CREDENTIALS);
+            callbackHandler = null;
+            principal = null;
+            credentials = null;
+            return logout();
+        }
+    }
+
+    /**
+     * Method which logs out a <code>Subject</code>.
+     * <p/>
+     * <p>An implementation of this method might remove/destroy a Subject's
+     * Principals and Credentials.
+     * <p/>
+     * <p/>
+     *
+     * @return true if this method succeeded, or false if this
+     *         <code>LoginModule</code> should be ignored.
+     * @throws LoginException if the logout fails
+     */
+    public boolean logout() throws LoginException {
+        Set thisPrincipals = subject.getPrincipals();
+        Set thisCredentials = subject.getPublicCredentials(SimpleCredentials.class);
+        if (thisPrincipals == null || thisCredentials == null
+                || thisPrincipals.isEmpty() || thisCredentials.isEmpty()) {
+            return false;
+        } else {
+            thisPrincipals.clear();
+            thisCredentials.clear();
+            return true;
+        }
+    }
+
+    /**
+     *
+     * @param principal
+     * @param credentials
+     * @return <code>true</code> if Credentails authenticate,
+     *         <code>false</code> if no <code>Authentication</code> can handle
+     *         the given <code>Credentials</code>
+     * @throws javax.security.auth.login.FailedLoginException
+     *          if the authentication failed.
+     * @see AbstractLoginModule#getAuthentication(java.security.Principal, javax.jcr.Credentials)
+     * @see AbstractLoginModule#authenticate(java.security.Principal, javax.jcr.Credentials)
+     */
+    protected boolean authenticate(Principal principal, Credentials credentials)
+            throws RepositoryException, FailedLoginException {
+
+        Authentication auth = getAuthentication(principal, credentials);
+        if(auth == null) {
+            return false;
+        } else if (auth.authenticate(credentials)){
+            return true;
+        }
+        throw new FailedLoginException();
+    }
+
+    /**
+     * @return a Collection of principals that contains the current user
+     * principal and all groups it is member of.
+     */
+    protected Set getPrincipals() {
+        // use ListOrderedSet instead of Hashset in order to maintain the order
+        // of principals (as in the Subject).
+        Set principals = new ListOrderedSet();
+        principals.add(principal);
+        Iterator groups = principalProvider.getGroupMembership(principal);
+        while (groups.hasNext()) {
+            principals.add(groups.next());
+        }
+        return principals;
+    }
+
+    /**
+     * Test if the current request is an Impersonation attempt. The default
+     * implementation returns <code>true</code> if an
+     * {@link #getImpersonatorSubject(Credentials) subject} for the
+     * impersonation can be retrieved.<p/>
+     *
+     * @param credentials potentially containing impersonation data
+     * @return true if this is an impersonation attempt
+     * @see #getImpersonatorSubject(Credentials)
+     */
+    protected boolean isImpersonation(Credentials credentials) {
+        return getImpersonatorSubject(credentials) != null;
+    }
+
+    /**
+     * Handles the impersonation of given Credentials.<p />
+     * Current implementation takes {@link User} for the given Principal and
+     * delegates the check to {@link Impersonation#allows(javax.security.auth.Subject)} }
+     *
+     * @param principal
+     * @param credentials
+     * @return false, if there is no User to impersonate,
+     *         true if impersonation is allowed
+     * @throws RepositoryException
+     * @throws FailedLoginException if credentials don't allow to impersonate to principal
+     */
+    abstract protected boolean impersonate(Principal principal, Credentials credentials)
+            throws RepositoryException, LoginException;
+
+    /**
+     *
+     * @param principal
+     * @param creds
+     * @return
+     * @throws RepositoryException
+     */
+    abstract protected Authentication getAuthentication(Principal principal, Credentials creds)
+            throws RepositoryException;
+
+    /**
+     * Method tries to acquire an Impersonator in the follwing order:
+     * <ul>
+     * <li> Try to access it from the {@link Credentials} via {@link SimpleCredentials#getAttribute(String)}</li>
+     * <li> Ask CallbackHandler for Impersonator with use of {@link ImpersonationCallback}.</li>
+     * </ul>
+     *
+     * @param credentials which, may contain an impersonation Subject
+     * @return impersonation subject or null if non contained
+     * @see #login()
+     * @see #impersonate(java.security.Principal, javax.jcr.Credentials)
+     */
+    protected Subject getImpersonatorSubject(Credentials credentials) {
+        Subject impersonator = null;
+        if (credentials == null) {
+            try {
+                ImpersonationCallback impers = new ImpersonationCallback();
+                callbackHandler.handle(new Callback[]{impers});
+                impersonator = impers.getImpersonator();
+            } catch (UnsupportedCallbackException e) {
+                log.warn(e.getCallback().getClass().getName() + " not supported: Unable to perform Impersonation.");
+            } catch (IOException e) {
+                log.error("Impersonation-Callback failed: " + e.getMessage() + ": Unable to perform Impersonation.");
+            }
+        } else if (credentials instanceof SimpleCredentials) {
+            SimpleCredentials sc = (SimpleCredentials) credentials;
+            impersonator = (Subject) sc.getAttribute(SecurityConstants.IMPERSONATOR_ATTRIBUTE);
+        }
+        return impersonator;
+    }
+
+    //------------------------------------------------------------< private >---
+    /**
+     * Method tries to resolve the {@link Credentials} used for login. It takes
+     * into account, that an authentication-extension of an allready
+     * authenticate {@link Subject} could take place<p/> Therefore the
+     * credentials are searchred for in the following search-order: <ol> <li>
+     * Ask CallbackHandler for Credentials with use of {@link
+     * CredentialsCallback}. Expects {@link CredentialsCallback#getCredentials}
+     * to return an instance of {@link SimpleCredentials}.</li> <li> Ask the
+     * Subject for its public credentials {@link Subject#getPublicCredentials(Class)},
+     * with {@link SimpleCredentials#getClass()} as argument.<p> This enables to
+     * preauthenticate the Subject.</li> </ol> NOTE: While the method signiture
+     * works with {@link Credentials} it actually searches and returns {@link
+     * SimpleCredentials}.<br> This is done to allow implementations to make use
+     * of this abstract class, without beeing bound to a {@link Credentials}
+     * implementation.
+     *
+     * @return Credentials or null if not found
+     * @see #login()
+     */
+    private Credentials getCredentials() {
+        SimpleCredentials credentials = null;
+        if (sharedState.containsKey(KEY_SIMPLE_CREDENTIALS)) {
+            credentials = (SimpleCredentials) sharedState.get(KEY_SIMPLE_CREDENTIALS);
+        } else {
+            try {
+                CredentialsCallback callback = new CredentialsCallback();
+                callbackHandler.handle(new Callback[]{callback});
+                Credentials creds = callback.getCredentials();
+                if (null != creds && creds instanceof SimpleCredentials) {
+                    credentials = (SimpleCredentials) creds;
+                    sharedState.put(KEY_SIMPLE_CREDENTIALS, credentials);
+                }
+            } catch (UnsupportedCallbackException e) {
+                log.warn("Credentials-Callback not supported try Name-Callback");
+            } catch (IOException e) {
+                log.error("Credentials-Callback failed: " + e.getMessage() + ": try Name-Callback");
+            }
+        }
+        // ask subject if still no credentials
+        if (null == credentials) {
+            Set preAuthCreds = subject.getPublicCredentials(SimpleCredentials.class);
+            if (!preAuthCreds.isEmpty()) {
+                credentials = (SimpleCredentials) subject.getPublicCredentials(SimpleCredentials.class).iterator().next();
+            }
+        }
+        return credentials;
+    }
+
+    /**
+     * Method supports tries to acquire a UserID in the follwing order: <ol>
+     * <li>Try to access it from the {@link Credentials} via {@link
+     * SimpleCredentials#getUserID()}</li>
+     * <li>Ask CallbackHandler for User-ID with use of {@link NameCallback}.</li>
+     * <li>Test if the 'sharedState' contains a login name.</li>
+     * <li>Test a defaultUserID is present in the LoginModule configuration.</li>
+     * <li>Fallback: return the anonymous UserID.</li>
+     * </ol>
+     *
+     * @param credentials which, may contain a User-ID
+     * @return The userId retrieved from the credentials or by any other means
+     * described above.
+     * @see #login()
+     */
+    private String getUserID(Credentials credentials) {
+        String userId = null;
+        if (credentials != null) {
+            if (credentials instanceof SimpleCredentials) {
+                userId = ((SimpleCredentials) credentials).getUserID();
+            } else {
+                try {
+                    NameCallback callback = new NameCallback("User-ID: ");
+                    callbackHandler.handle(new Callback[]{callback});
+                    userId = callback.getName();
+                } catch (UnsupportedCallbackException e) {
+                    log.warn("Credentials- or NameCallback must be supported");
+                } catch (IOException e) {
+                    log.error("Name-Callback failed: " + e.getMessage());
+                }
+            }
+        }
+        if (userId == null && sharedState.containsKey(KEY_LOGIN_NAME)) {
+            userId = (String) sharedState.get(KEY_LOGIN_NAME);
+        }
+
+        // still no userId -> if a defaultUserID has been specified or return
+        // the anonymous UserID.
+        // TODO: check again if correct when used with 'extendedAuth'
+        if (userId == null) {
+            if (defaultUserId != null) {
+                userId = defaultUserId;
+            } else {
+                userId = anonymousId;
+            }
+        }
+
+        return userId;
+    }
+
+    /**
+     * Indicate if the given Credentials are considered to be anonymous.
+     *
+     * @param credentials
+     * @return true if is anonymous
+     */
+    private boolean isAnonymous(Credentials credentials) {
+        // TODO: check again. former simple-login-module treated 'null' as anonymous and had no anonymous config entry.
+        String userId = getUserID(credentials);
+        if (anonymousId == null) {
+            return userId == null;
+        } else {
+            return anonymousId.equals(userId);
+        }
+    }
+
+    /**
+     * Authentication process associates a Principal to Credentials<br>
+     * This method resolves the Principal for the given Credentials. If there
+     * is no Principal for the Credentials, the LoginModule should be ignored.<p>
+     * This Abstract implementation uses the {@link PrincipalProvider} configured
+     * for it, to resolve this association.
+     * It takes the {@link PrincipalProvider#findPrincipals(String)} for the User-ID
+     * resolved by  {@link #getUserID(Credentials)}
+     *
+     * @param credentials
+     * @return if credentials are associated to one or null if none found
+     */
+    private Principal getPrincipal(Credentials credentials) {
+        Principal principal = null;
+        String userId = isAnonymous(credentials) ? anonymousId : getUserID(credentials);
+        PrincipalIterator res = principalProvider.findPrincipals(userId, PrincipalManager.SEARCH_TYPE_NOT_GROUP);
+        if (res.hasNext()) {
+            principal = res.nextPrincipal();
+        } // no matching principal -> return null
+        return principal;
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContext.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContext.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContext.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+/**
+ * An authentication context used to authenticate users. It is similar to JAAS' <code>LoginContext</code>
+ * but can work in a non-JAAS environment.
+ * <p>
+ * This class is abstract and has two implementations:
+ * <ul>
+ *   <li>{@link JAASAuthContext} which delegates to a regular JAAS <code>LoginContext</code></li>
+ *   <li>{@link LocalAuthContext} which implements authentication using a locally-defined
+ *       JAAS <code>LoginModule</code></li>
+ * </ul>
+ */
+public abstract interface AuthContext {
+
+    /**
+     * Perform the authentication and, if successful, associate Principals and Credentials
+     * with the authenticated<code>Subject</code>.
+     *
+     * @see LoginContext#login()
+     * @throws LoginException if the authentication fails.
+     */
+    public abstract void login() throws LoginException;
+
+    /**
+     * Return the authenticated Subject.
+     *
+     * @see LoginContext#getSubject()
+     * @return the authenticated Subject or <code>null</code> if authentication failed.
+     */
+    public abstract Subject getSubject();
+
+    /**
+     * Logout the <code>Subject</code>.
+     *
+     * @see LoginContext#logout()
+     * @exception LoginException if the logout fails.
+     */
+    public abstract void logout() throws LoginException;
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContext.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.jackrabbit.core.config.LoginModuleConfig;
+import org.apache.jackrabbit.core.security.principal.PrincipalProviderRegistry;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * A AuthContextProvider selects how the current request for login is handled.
+ * It selects the mechanism and set-up according configuration.<br>
+ * The handler selects if the JAAS-configuration
+ * {@link javax.security.auth.login.Configuration} is taken or the fall-back as
+ * configured via {@link org.apache.jackrabbit.core.config.RepositoryConfig}.<p>
+ * This implementaion selects JAAS under the following condition:
+ * <ul>
+ * <li>a JAAS Login-{@link javax.security.auth.login.Configuration} is available
+ * <li>the configuration contains the configured application name
+ * </ul>
+ * If the conditions are not met <b>AND</b> a LoginModule is configured in
+ * {@link org.apache.jackrabbit.core.config.RepositoryConfig}, that one is taken.
+ */
+public class AuthContextProvider {
+
+    private boolean initialized;
+
+    /**
+     * configuration state -> if a JAAS Configuration exists for this application
+     */
+    private boolean isJAAS;
+
+    /**
+     * Configuration of the optional local LoginModule
+     */
+    private final LoginModuleConfig config;
+
+    /**
+     * Application Name for the LoginConfig entry
+     */
+    private final String appName;
+
+    /**
+     * @param appName LoginConfig application name used for this instance
+     * @param config optional LoginModule-configuration to use without JAAS
+     */
+    public AuthContextProvider(String appName, LoginModuleConfig config) {
+        this.appName = appName;
+        this.config = config;
+    }
+
+    /**
+     * @param credentials to authenticate
+     * @param subject subject to extend authentication
+     * @param session Session to pass to the login-modules
+     * @return context of for authentication and log-out
+     * @throws RepositoryException in case neither an <code>JAASContext</code>
+     * nor a <code>LocalContext</code> can be successfully created.
+     */
+    public AuthContext getAuthContext(Credentials credentials,
+                                      Subject subject,
+                                      Session session,
+                                      PrincipalProviderRegistry principalProviderRegistry)
+            throws RepositoryException {
+
+        CallbackHandler cbHandler = new CallbackHandlerImpl(credentials, session, principalProviderRegistry);
+
+        if (isJAAS()) {
+            return new JAASAuthContext(appName, cbHandler, subject);
+        } else if (isLocal()){
+            return new LocalAuthContext(config, cbHandler, subject);
+        } else {
+            throw new RepositoryException("No Login-Configuration");
+        }
+    }
+
+    /**
+     * @return true if a application entry is available in a JAAS- {@link Configuration}
+     */
+    public boolean isJAAS() {
+        if (!initialized) {
+            AppConfigurationEntry[] entries = getJAASConfig();
+            isJAAS = null!=entries && entries.length>0;
+            initialized = true;
+        }
+        return isJAAS;
+    }
+
+    /**
+     * @return true if {@link #isJAAS()} is false and a login-module is configured
+     */
+    public boolean isLocal() {
+        return !(isJAAS() || config == null);
+    }
+
+    /**
+     * @return options configured for the LoginModules to use
+     */
+    public Properties[] getModuleConfig() {
+        Properties[] props = new Properties[0];
+        if (isLocal()) {
+            props = new Properties[] {config.getParameters()};
+        } else {
+            AppConfigurationEntry[] entries = getJAASConfig();
+            if(entries != null) {
+                List tmp = new ArrayList(entries.length);
+                for(int i=0;i<entries.length;i++) {
+                    Map opt = entries[i].getOptions();
+                    if (opt != null) {
+                        Properties prop = new Properties();
+                        prop.putAll(opt);
+                        tmp.add(prop);
+                    }
+                }
+                props = (Properties[]) tmp.toArray(new Properties[tmp.size()]);
+            }
+        }
+        return props;
+    }
+
+    /**
+     * @return all JAAS-Login Modules for this application or null if none
+     */
+    private AppConfigurationEntry[] getJAASConfig() {
+
+        // check if jaas-loginModule or fallback is configured
+        Configuration logins = null;
+        try {
+            logins = Configuration.getConfiguration();
+        } catch (Exception e) {
+            // means no JAAS configuration file OR no permission to read it
+        }
+        if (logins != null) {
+            try {
+                return logins.getAppConfigurationEntry(appName);
+            } catch (Exception e) {
+                // WLP 9.2.0 throws IllegalArgumentException for unknown appName
+            }
+        }
+        return null;
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/Authentication.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/Authentication.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/Authentication.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/Authentication.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Credentials;
+
+/**
+ * The <code>Authentication</code> interface defines methods to validate
+ * {@link javax.jcr.Credentials Credentials} upon authentication. The validation
+ * dependants on the authentication mechanism used, i.e.
+ * <ul>
+ * <li>comparison of UserID/password pair retrieved from the given Credentials
+ * with Credentials stored for a particular user,</li>
+ * <li>bind to a LDAP with a given ID,</li>
+ * <li>validation of a SSO ticket.</li>
+ * </ul>
+ *
+ */
+public interface Authentication {
+
+    /**
+     * An Authentication may only be able to handle certain types of
+     * <code>Credentials</code> as the authentication process is tightly coupled
+     * to the semantics of the <code>Credentials</code>.
+     * E.g.: A ticket based <code>Authentication</code> is dependant on a
+     * Credentials implementation which allows access to this ticket.
+     *
+     * @param credentials in questions
+     * @return <code>true</code> if the current Authentication handles the given Credentials
+     */
+    boolean canHandle(Credentials credentials);
+
+    /**
+     * True if the Credentials identify the <code>User</code> related to this
+     * Authentication.
+     *
+     * @param credentials to verify
+     * @return <code>true</code> if <code>Credentials</code> identify the
+     * <code>User</code>.
+     * @throws RepositoryException
+     */
+    boolean authenticate(Credentials credentials) throws RepositoryException;
+
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/Authentication.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/Authentication.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CallbackHandlerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CallbackHandlerImpl.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CallbackHandlerImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CallbackHandlerImpl.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.principal.PrincipalProviderRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Credentials;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import java.io.IOException;
+
+/**
+ * CallbackHandler that deals with the following callbacks:
+ * <ul>
+ * <li>{@link NameCallback}
+ * <li>{@link PasswordCallback}
+ * <li>{@link CredentialsCallback}
+ * <li>{@link ImpersonationCallback}
+ * <li>{@link RepositoryCallback}
+ * </ul>
+ */
+public class CallbackHandlerImpl implements CallbackHandler {
+
+    private static final Logger log = LoggerFactory.getLogger(CallbackHandlerImpl.class);
+
+    private final Session session;
+    private final Credentials credentials;
+    private final PrincipalProviderRegistry principalProviderRegistry;
+
+    /**
+     * Instanciate with the data needed to handle callbacks
+     * @param credentials
+     * @param session
+     */
+    public CallbackHandlerImpl(Credentials credentials, Session session,
+                               PrincipalProviderRegistry principalProviderRegistry) {
+        this.credentials = credentials;
+        this.session = session;
+        this.principalProviderRegistry = principalProviderRegistry;
+
+        if (session == null) {
+            log.debug("Session is null -> CallbackHandler won't be able to handle RepositoryCallback.");
+        }
+        if (principalProviderRegistry == null) {
+            log.debug("PrincipalProviderRegistry is null -> CallbackHandler won't be able to handle RepositoryCallback.");            
+        }
+    }
+
+    /**
+     * @param callbacks
+     * @throws IOException
+     * @throws UnsupportedCallbackException
+     * @see CallbackHandler#handle(Callback[])
+     */
+    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+
+        for (int i = 0; i < callbacks.length; i++) {
+            Callback callback = callbacks[i];
+
+            if (callback instanceof CredentialsCallback) {
+                ((CredentialsCallback) callback).setCredentials(credentials);
+            } else if (callback instanceof RepositoryCallback) {
+                /*
+                if callback handler has been created with null session or
+                null principalProviderRegistry this handler cannot properly
+                deal with RepositoryCallback
+                */
+                if (session == null || principalProviderRegistry == null) {
+                    throw new UnsupportedCallbackException(callback);
+                }
+                ((RepositoryCallback) callback).setSession(session);
+                ((RepositoryCallback) callback).setPrincipalProviderRegistry(principalProviderRegistry);
+            } else if (credentials != null && credentials instanceof SimpleCredentials) {
+                SimpleCredentials simpleCreds = (SimpleCredentials) credentials;
+                if (callback instanceof NameCallback) {
+                    String userId = simpleCreds.getUserID();
+                    ((NameCallback) callback).setName(userId);
+                } else if (callback instanceof PasswordCallback) {
+                    char[] pw = simpleCreds.getPassword();
+                    ((PasswordCallback) callback).setPassword(pw);
+                } else if (callback instanceof ImpersonationCallback) {
+                    Object impersAttr = simpleCreds.getAttribute(SecurityConstants.IMPERSONATOR_ATTRIBUTE);
+                    ((ImpersonationCallback) callback).setImpersonator(impersAttr);
+                } else {
+                    throw new UnsupportedCallbackException(callback);
+                }
+            } else {
+                throw new UnsupportedCallbackException(callback);
+            }
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CallbackHandlerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CallbackHandlerImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CredentialsCallback.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CredentialsCallback.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CredentialsCallback.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CredentialsCallback.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import javax.jcr.Credentials;
+import javax.security.auth.callback.Callback;
+import java.io.Serializable;
+
+/**
+ * A <code>CredentialsCallback</code>
+ */
+public class CredentialsCallback implements Callback, Serializable {
+
+    private Credentials credentials;
+
+    /**
+     * Get the retrieved credentials.
+     *
+     * @return the retrieved credentials (which may be null)
+     */
+    public Credentials getCredentials() {
+        return credentials;
+    }
+
+    /**
+     * Set the retrieved credentials.
+     *
+     * @param credentials the retrieved credentials (which may be null)
+     */
+    public void setCredentials(Credentials credentials) {
+        this.credentials = credentials;
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CredentialsCallback.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CredentialsCallback.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.util.Text;
+
+import javax.jcr.Credentials;
+import javax.jcr.SimpleCredentials;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Crypted variant of the {@link javax.jcr.SimpleCredentials}.
+ */
+public class CryptedSimpleCredentials implements Credentials {
+
+    private final String algorithm;
+    private final String cryptedPassword;
+    private final String userId;
+    private final Map attributes;
+
+    /**
+     * Take {@link javax.jcr.SimpleCredentials SimpleCredentials} and
+     * digest the password if it is plain-text
+     *
+     * @param credentials
+     * @throws NoSuchAlgorithmException
+     * @throws UnsupportedEncodingException
+     */
+    public CryptedSimpleCredentials(SimpleCredentials credentials)
+            throws NoSuchAlgorithmException, UnsupportedEncodingException {
+        userId = credentials.getUserID();
+        if (userId == null || userId.length() == 0) {
+            throw new IllegalArgumentException();
+        }
+        char[] pwd = credentials.getPassword();
+        if (pwd == null) {
+            throw new IllegalArgumentException();
+        }
+        String password = new String(pwd);
+        String algo =  getAlgorithm(password);
+        if (algo == null) {
+            // password is plain text
+            algorithm = SecurityConstants.DEFAULT_DIGEST;
+            cryptedPassword = crypt(algorithm, password);
+        } else {
+            // password is already encrypted
+            algorithm = algo;
+            cryptedPassword = password;
+        }
+
+        String[] attNames = credentials.getAttributeNames();
+        attributes = new HashMap(attNames.length);
+        for (int i = 0; i < attNames.length; i++) {
+            attributes.put(attNames[i], credentials.getAttribute(attNames[i]));
+        }
+    }
+
+    public CryptedSimpleCredentials(String userId, String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+        if (userId == null || userId.length() == 0) {
+            throw new IllegalArgumentException();
+        }
+        if (password == null) {
+            throw new IllegalArgumentException();
+        }
+        this.userId = userId;
+        String algo =  getAlgorithm(password);
+        if (algo == null) {
+            // password is plain text
+            algorithm = SecurityConstants.DEFAULT_DIGEST;
+            cryptedPassword = crypt(algorithm, password);
+        } else {
+            // password is already encrypted
+            algorithm = algo;
+            cryptedPassword = password;
+        }
+        attributes = Collections.EMPTY_MAP;
+    }
+
+    public String getUserID() {
+        return userId;
+    }
+
+    public Object getAttribute(String name) {
+        return attributes.get(name);
+    }
+
+    public String[] getAttributeNames() {
+        return (String[]) attributes.keySet().toArray(new String[attributes.size()]);
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    public String getPassword() {
+        return cryptedPassword;
+    }
+
+    /**
+     * Compair this instance with an instance of SimpleCredentials.
+     * If one the other Credentials' Password is plain-text treies to encode
+     * it with the current Digest.
+     *
+     * @param credentials
+     * @return true if {@link SimpleCredentials#getUserID() UserID}
+     *              and {@link SimpleCredentials#getPassword() Password} match
+     * @throws NoSuchAlgorithmException
+     * @throws UnsupportedEncodingException
+     */
+    public boolean matches(SimpleCredentials credentials)
+            throws NoSuchAlgorithmException, UnsupportedEncodingException {
+
+        if (getUserID().matches(credentials.getUserID())) {
+            String toMatch = new String(credentials.getPassword());
+            String algr = getAlgorithm(toMatch);
+
+            if (algr == null && algorithm != null) {
+                // uncrypted pw to match -> crypt with algorithm present here.
+                return crypt(algorithm, toMatch).equals(cryptedPassword);
+            } else if (algr != null && algorithm == null) {
+                // crypted pw to match but unkown algorithm here -> crypt this pw
+                return crypt(cryptedPassword, algr).equals(toMatch);
+            }
+
+            // both pw to compare define a algorithm and are crypted
+            // -> simple comparison of the 2 password strings.
+            return toMatch.equals(cryptedPassword);
+        }
+        return false;
+    }
+
+    private static String crypt(String algorithm, String pwd)
+            throws NoSuchAlgorithmException, UnsupportedEncodingException {
+
+        StringBuffer password = new StringBuffer();
+        password.append("{").append(algorithm).append("}");
+        password.append(Text.digest(algorithm, pwd.getBytes("UTF-8")));
+        return password.toString();
+    }
+
+    private static String getAlgorithm(String password) {
+        int end = password.indexOf("}");
+        if (password.startsWith("{") && end>0) {
+            return password.substring(1,end);
+        } else {
+            return null;
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Impersonation;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+import java.security.Principal;
+import java.util.Map;
+
+/**
+ * The <code>DefaultLoginModule</code> authenticates Credentials related to
+ * a {@link User} of the Repository<br>
+ * In any other case it is marked to be ignored.<p>
+ * This Module can deal only with <code>SimpleCredentials</code> since it
+ * uses by default the {@link SimpleCredentialsAuthentication}. Impersonation is
+ * delegated to the <code>User</code>'s {@link User#getImpersonation()
+ * Impersonation} object
+ *
+ * @see AbstractLoginModule
+ */
+public class DefaultLoginModule extends AbstractLoginModule {
+
+    private static final Logger log = LoggerFactory.getLogger(AbstractLoginModule.class);
+
+    private UserManager userManager;
+
+    /**
+     * Retrieves the user manager from the specified session. If this fails
+     * this login modules initialization must fail.
+     *
+     * @see AbstractLoginModule#doInit(CallbackHandler, Session, Map)
+     */
+    protected void doInit(CallbackHandler callbackHandler, Session session, Map options) throws LoginException {
+        if (!(session instanceof SessionImpl)) {
+            throw new LoginException("Unable to initialize LoginModule: SessionImpl expected.");
+        }
+        try {
+            userManager = ((SessionImpl) session).getUserManager();
+            log.debug("- UserManager -> '" + userManager.getClass().getName() + "'");
+        } catch (RepositoryException e) {
+            throw new LoginException("Unable to initialize LoginModule: " + e.getMessage());
+        }
+    }
+
+    protected Authentication getAuthentication(Principal principal, Credentials creds) throws RepositoryException {
+        Authorizable authrz = userManager.getAuthorizable(principal);
+        if (authrz == null || authrz.isGroup()) {
+            return null;
+        }
+        Authentication authentication = new SimpleCredentialsAuthentication((User) authrz);
+        if (authentication.canHandle(creds)) {
+            return authentication;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Handles the impersonation of given Credentials.<p />
+     * Current implementation takes {@link User} for the given Principal and
+     * delegates the check to {@link Impersonation#allows(javax.security.auth.Subject)}
+     *
+     * @param principal
+     * @param credentials
+     * @return false, if there is no User to impersonate,
+     *         true if impersonation is allowed
+     * @throws javax.jcr.RepositoryException
+     * @throws javax.security.auth.login.FailedLoginException
+     *                                       if credentials don't allow to impersonate to principal
+     * @see AbstractLoginModule#impersonate(Principal, Credentials)
+     */
+    protected boolean impersonate(Principal principal, Credentials credentials)
+            throws RepositoryException, FailedLoginException {
+
+        Authorizable authrz = userManager.getAuthorizable(principal);
+        if (authrz == null || authrz.isGroup()) {
+            return false;
+        }
+        Subject impersSubject = getImpersonatorSubject(credentials);
+        User user = (User) authrz;
+        if (user.getImpersonation().allows(impersSubject)) {
+            return true;
+        } else {
+            throw new FailedLoginException("attempt to impersonate denied for " + principal.getName());
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/ImpersonationCallback.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/ImpersonationCallback.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/ImpersonationCallback.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/ImpersonationCallback.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+
+/**
+ * Callback for a {@link javax.security.auth.callback.CallbackHandler} to ask
+ * for a the impersonating {@link javax.security.auth.Subject} to create a
+ * {@link javax.jcr.Session} to access the {@link javax.jcr.Repository}.
+ */
+public class ImpersonationCallback implements Callback {
+
+    /**
+     * The impersonating {@link Subject}.
+     * @see #setImpersonator(Object)
+     * @see #getImpersonator()
+     */
+    private Subject impersonator;
+
+    /**
+     * Sets the impersonator in this callback.
+     *
+     * @param impersonator The impersonator to set on this callback. If this is
+     *      not a {@link Subject} this method does nothing.
+     */
+    public void setImpersonator(Object impersonator) {
+        if (impersonator instanceof Subject) {
+            this.impersonator = (Subject) impersonator;
+        }
+    }
+
+    /**
+     * Returns the impersonator {@link Subject} set on this callback or
+     * <code>null</code> if not set.
+     */
+    public Subject getImpersonator() {
+        return impersonator;
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/ImpersonationCallback.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/ImpersonationCallback.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/JAASAuthContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/JAASAuthContext.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/JAASAuthContext.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/JAASAuthContext.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+/**
+ * Implements the common {@link AuthContext} interface for the JAAS environment.
+ *
+ * @see AuthContext
+ */
+public class JAASAuthContext implements AuthContext {
+
+    private LoginContext context;
+
+    /**
+     * @param appName   application name in JAAS Login-Configuration to use
+     * @param cbHandler CallbackHandler for login-modules
+     * @param subject   to extend authentication
+     */
+    JAASAuthContext(String appName, CallbackHandler cbHandler, Subject subject) {
+
+        // make sure we are using our own context class loader when we
+        // instantiate a LoginContext. See bug# 14329.
+        Thread current = Thread.currentThread();
+        ClassLoader orig = current.getContextClassLoader();
+        try {
+            current.setContextClassLoader(JAASAuthContext.class.getClassLoader());
+            if (null == subject) {
+                context = new LoginContext(appName, cbHandler);
+            } else {
+                context = new LoginContext(appName, subject, cbHandler);
+            }
+        } catch (LoginException e) {
+            //all caseses it is thrown are checked -> ignore
+        } finally {
+            current.setContextClassLoader(orig);
+        }
+    }
+
+    public void login() throws LoginException {
+        context.login();
+    }
+
+    public Subject getSubject() {
+        return context.getSubject();
+    }
+
+    public void logout() throws LoginException {
+        context.logout();
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/JAASAuthContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/JAASAuthContext.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/LocalAuthContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/LocalAuthContext.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/LocalAuthContext.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/LocalAuthContext.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.jackrabbit.core.config.ConfigurationException;
+import org.apache.jackrabbit.core.config.LoginModuleConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import java.util.HashMap;
+
+/**
+ * Provide AuthContext interface, for a JAAS-LoginModule not running in
+ * a {@link javax.security.auth.login.LoginContext}
+ *
+ * @see AuthContext
+ */
+public class LocalAuthContext implements AuthContext {
+
+    private static final Logger log = LoggerFactory.getLogger(LocalAuthContext.class);
+
+    private Subject subject;
+
+    private LoginModuleConfig config;
+
+    private LoginModule module;
+
+    private final CallbackHandler cbHandler;
+
+    /**
+     * Create Context and set Subject to extend its authentication
+     *
+     * @param config    Condiguration to be used for the LoginModule
+     * @param cbHandler CallbackHandler for the LoginModule
+     * @param subject   Subject if a pre-authenticated exists
+     */
+    LocalAuthContext(LoginModuleConfig config, CallbackHandler cbHandler,
+                     Subject subject) {
+        this.config = config;
+        this.cbHandler = cbHandler;
+        this.subject = (null == subject) ? new Subject() : subject;
+    }
+
+    public void login() throws LoginException {
+        try {
+            module = config.getLoginModule();
+        } catch (ConfigurationException e) {
+            throw new LoginException(e.getMessage());
+        }
+        module.initialize(subject, cbHandler, new HashMap(), config.getParameters());
+        try {
+            if (!(module.login() && module.commit())) {
+                throw new FailedLoginException("LoginModule ignored Credentials");
+            }
+        } catch (LoginException le) {
+            module.abort();
+            throw le;
+        } catch (Exception e) {
+            module.abort();
+            LoginException le = new LoginException("LoginModule could not perform authentication: " +
+                    e.getMessage());
+            le.initCause(e);
+            log.debug("Login failed to runtime-exception: ", e);
+            throw le;
+        }
+    }
+
+    public Subject getSubject() {
+        return subject;
+    }
+
+    public void logout() throws LoginException {
+        if (subject != null) {
+            module.logout();
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/LocalAuthContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/LocalAuthContext.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/RepositoryCallback.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/RepositoryCallback.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/RepositoryCallback.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/RepositoryCallback.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.jackrabbit.core.security.principal.PrincipalProviderRegistry;
+
+import javax.jcr.Session;
+import javax.security.auth.callback.Callback;
+
+/**
+ * Callback for a {@link javax.security.auth.callback.CallbackHandler} to ask for
+ * a {@link Session} to access the {@link javax.jcr.Repository}
+ */
+public class RepositoryCallback implements Callback {
+
+    private Session session;
+    private PrincipalProviderRegistry principalProviderRegistry;
+
+    public void setSession(Session session) {
+        this.session = session;
+    }
+
+    public Session getSession() {
+        return session;
+    }
+
+    public void setPrincipalProviderRegistry(PrincipalProviderRegistry principalProviderRegistry) {
+        this.principalProviderRegistry = principalProviderRegistry;
+    }
+
+    public PrincipalProviderRegistry getPrincipalProviderRegistry() {
+        return principalProviderRegistry;
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/RepositoryCallback.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/RepositoryCallback.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthentication.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthentication.java?rev=638834&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthentication.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthentication.java Wed Mar 19 06:56:13 2008
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.jackrabbit.api.security.user.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.SimpleCredentials;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * This {@link Authentication} implementation handles all
+ * {@link javax.jcr.SimpleCredentials SimpleCredentials} stored
+ * for a given {@link org.apache.jackrabbit.api.security.user.User#getCredentials() User}.<br>
+ * For verification the <code>SimpleCredentials</code>
+ * {@link javax.jcr.SimpleCredentials#getUserID() UserID} and
+ * {@link javax.jcr.SimpleCredentials#getPassword() Password} are tested.
+ * If both are equal to the ones stored at the User, verification succeeded.
+ *
+ * @see org.apache.jackrabbit.core.security.authentication.Authentication
+ * @see javax.jcr.SimpleCredentials
+ */
+class SimpleCredentialsAuthentication implements Authentication {
+
+    private static final Logger log = LoggerFactory.getLogger(SimpleCredentialsAuthentication.class);
+
+    private final Collection credentialSet = new HashSet();
+
+    /**
+     * Create an Authentication for this User
+     *
+     * @param user to create the Authentication for
+     * @throws javax.jcr.RepositoryException
+     */
+    SimpleCredentialsAuthentication(User user) throws RepositoryException {
+        for(Iterator it = user.getCredentials(); it.hasNext();) {
+            Credentials creds = (Credentials) it.next();
+            if (creds instanceof CryptedSimpleCredentials) {
+                credentialSet.add(creds);
+            } else if (creds instanceof SimpleCredentials) {
+                try {
+                    credentialSet.add(new CryptedSimpleCredentials((SimpleCredentials) creds));
+                } catch (NoSuchAlgorithmException e) {
+                    throw new RepositoryException(e);
+                } catch (UnsupportedEncodingException e) {
+                    throw new RepositoryException(e);
+                }
+            }
+        }
+    }
+
+    //------------------------------------------------< Authentication >--------
+    /**
+     * This Authentication is able to handle the validation of SimpleCredentials.
+     *
+     * @param credentials to test
+     * @return <code>true</code> if the given Credentials are of type
+     *         {@link javax.jcr.SimpleCredentials SimpleCredentials} and if the
+     *         <code>User</code> used to construct this <code>Autentication</code>
+     *         has any SimpleCredentials
+     * @see Authentication#canHandle(Credentials)
+     */
+    public boolean canHandle(Credentials credentials) {
+        return !credentialSet.isEmpty() && credentials instanceof SimpleCredentials;
+    }
+
+    /**
+     * Compairs any of the <code>SimpleCredentials</code> of the <code>User</code>
+     * with the one given.<br>
+     * If both, UserID and Password of the credentials are equal, the authentication
+     * succeded and <code>true</code> is returned;
+     *
+     * @param credentials
+     * @return true if the given Credentials' UserID/Password pair match any
+     * of the credentials attached to the user this SimpleCredentialsAuthentication has
+     * been built for.
+     * @throws RepositoryException
+     */
+    public boolean authenticate(Credentials credentials) throws RepositoryException {
+        if (!(credentials instanceof SimpleCredentials)) {
+            throw new RepositoryException("SimpleCredentials expected. Cannot handle " + credentials.getClass().getName());
+        }
+
+        for (Iterator it = credentialSet.iterator(); it.hasNext();) {
+            try {
+                CryptedSimpleCredentials creds = (CryptedSimpleCredentials) it.next();
+                if (creds.matches((SimpleCredentials) credentials)) {
+                    return true;
+                }
+            } catch (NoSuchAlgorithmException e) {
+                log.debug("Failed to verify Credentials with {}: {} -> test next", credentials.toString(), e);
+            } catch (UnsupportedEncodingException e) {
+                log.debug("Failed to verify Credentials with {}: {} -> test next", credentials.toString(), e);
+            }
+        }
+        return false;
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthentication.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthentication.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url



Mime
View raw message