You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by ad...@apache.org on 2009/03/11 06:40:54 UTC
svn commit: r752380 [5/9] - in /incubator/jsecurity/trunk: ./
core/src/org/apache/ki/ core/src/org/apache/ki/aop/
core/src/org/apache/ki/authc/ core/src/org/apache/ki/authc/credential/
core/src/org/apache/ki/authc/pam/ core/src/org/apache/ki/authz/ cor...
Copied: incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SessionsSecurityManager.java (from r752240, incubator/jsecurity/trunk/core/src/org/ki/mgt/SessionsSecurityManager.java)
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SessionsSecurityManager.java?p2=incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SessionsSecurityManager.java&p1=incubator/jsecurity/trunk/core/src/org/ki/mgt/SessionsSecurityManager.java&r1=752240&r2=752380&rev=752380&view=diff
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/ki/mgt/SessionsSecurityManager.java (original)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SessionsSecurityManager.java Wed Mar 11 05:40:38 2009
@@ -16,28 +16,29 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.ki.mgt;
-
-import org.ki.authz.HostUnauthorizedException;
-import org.ki.cache.CacheManagerAware;
-import org.ki.session.InvalidSessionException;
-import org.ki.session.Session;
-import org.ki.session.SessionListener;
-import org.ki.session.SessionListenerRegistrar;
-import org.ki.session.mgt.AbstractSessionManager;
-import org.ki.session.mgt.AbstractValidatingSessionManager;
-import org.ki.session.mgt.DefaultSessionManager;
-import org.ki.session.mgt.SessionManager;
-import org.ki.util.LifecycleUtils;
+package org.apache.ki.mgt;
import java.io.Serializable;
import java.net.InetAddress;
import java.util.Collection;
import java.util.Date;
+import org.apache.ki.authz.HostUnauthorizedException;
+import org.apache.ki.cache.CacheManagerAware;
+import org.apache.ki.session.InvalidSessionException;
+import org.apache.ki.session.Session;
+import org.apache.ki.session.SessionListener;
+import org.apache.ki.session.SessionListenerRegistrar;
+import org.apache.ki.session.mgt.AbstractSessionManager;
+import org.apache.ki.session.mgt.AbstractValidatingSessionManager;
+import org.apache.ki.session.mgt.DefaultSessionManager;
+import org.apache.ki.session.mgt.SessionManager;
+import org.apache.ki.util.LifecycleUtils;
+
+
/**
* JSecurity support of a {@link SecurityManager} class hierarchy that delegates all
- * {@link org.ki.session.Session session} operations to a wrapped {@link SessionManager SessionManager}
+ * {@link org.apache.ki.session.Session session} operations to a wrapped {@link org.apache.ki.session.mgt.SessionManager SessionManager}
* instance. That is, this class implements the methods in the
* {@link SessionManager SessionManager} interface, but in reality, those methods are merely passthrough calls to
* the underlying 'real' {@code SessionManager} instance.
@@ -95,14 +96,14 @@
* Returns this security manager's internal delegate {@link SessionManager SessionManager}.
*
* @return this security manager's internal delegate {@link SessionManager SessionManager}.
- * @see #setSessionManager(org.ki.session.mgt.SessionManager) setSessionManager
+ * @see #setSessionManager(org.apache.ki.session.mgt.SessionManager) setSessionManager
*/
public SessionManager getSessionManager() {
return this.sessionManager;
}
/**
- * Calls {@link AuthorizingSecurityManager#afterCacheManagerSet() super.afterCacheManagerSet()} and then immediately calls
+ * Calls {@link org.apache.ki.mgt.AuthorizingSecurityManager#afterCacheManagerSet() super.afterCacheManagerSet()} and then immediately calls
* {@link #applyCacheManagerToSessionManager() applyCacheManagerToSessionManager()} to ensure the
* <code>CacheManager</code> is applied to the SessionManager as necessary.
*/
@@ -165,13 +166,13 @@
/**
* Passthrough configuration property to the underlying {@link AbstractSessionManager AbstractSessionManager}
* instance. Please read the
- * {@link org.ki.session.mgt.AbstractSessionManager#getGlobalSessionTimeout() AbstractSessionManager.getGlobalSessionTimeout()}
+ * {@link org.apache.ki.session.mgt.AbstractSessionManager#getGlobalSessionTimeout() AbstractSessionManager.getGlobalSessionTimeout()}
* for more.
*
* @return the time in milliseconds that any {@link Session Session} may remain idle before expiring.
* @throws IllegalStateException if the underlying {@code SessionManager} instance is not a subclass of
* {@link AbstractSessionManager AbstractSessionManager}.
- * @see org.ki.session.mgt.AbstractSessionManager#getGlobalSessionTimeout()
+ * @see org.apache.ki.session.mgt.AbstractSessionManager#getGlobalSessionTimeout()
*/
public long getGlobalSessionTimeout() {
assertSessionManager(AbstractSessionManager.class);
@@ -181,13 +182,13 @@
/**
* Passthrough configuration property to the underlying {@link AbstractSessionManager AbstractSessionManager}
* instance. Please read the
- * {@link org.ki.session.mgt.AbstractSessionManager#setGlobalSessionTimeout(long) AbstractSessionManager.setGlobalSessionTimeout(long)}
+ * {@link org.apache.ki.session.mgt.AbstractSessionManager#setGlobalSessionTimeout(long) AbstractSessionManager.setGlobalSessionTimeout(long)}
* for more.
*
* @param globalSessionTimeout the time in milliseconds that any {@link Session Session} may remain idle before expiring.
* @throws IllegalStateException if the underlying {@code SessionManager} instance is not a subclass of
- * {@link AbstractSessionManager AbstractSessionManager}.
- * @see org.ki.session.mgt.AbstractSessionManager#setGlobalSessionTimeout(long)
+ * {@link org.apache.ki.session.mgt.AbstractSessionManager AbstractSessionManager}.
+ * @see org.apache.ki.session.mgt.AbstractSessionManager#setGlobalSessionTimeout(long)
*/
public void setGlobalSessionTimeout(long globalSessionTimeout) {
assertSessionManager(AbstractSessionManager.class);
@@ -195,19 +196,19 @@
}
/**
- * Passthrough configuration property to the wrapped {@link AbstractValidatingSessionManager} - if it should
+ * Passthrough configuration property to the wrapped {@link org.apache.ki.session.mgt.AbstractValidatingSessionManager} - if it should
* automatically create a new session when an invalid session is referenced. The default value unless
* overridden by this method is <code>true</code> for developer convenience and to match what most people are
* accustomed based on years of servlet container behavior.
* <p/>
* When true (the default), the wrapped {@link AbstractValidatingSessionManager} implementation throws an
- * {@link org.ki.session.ReplacedSessionException ReplacedSessionException} to the caller whenever a new
+ * {@link org.apache.ki.session.ReplacedSessionException ReplacedSessionException} to the caller whenever a new
* session is created so the caller can receive the new session ID and react accordingly for future
* {@link SessionManager SessionManager} method invocations.
*
* @param autoCreate if the wrapped {@link AbstractValidatingSessionManager} should automatically create a new
* session when an invalid session is referenced
- * @see org.ki.session.mgt.AbstractValidatingSessionManager#setAutoCreateAfterInvalidation(boolean)
+ * @see org.apache.ki.session.mgt.AbstractValidatingSessionManager#setAutoCreateAfterInvalidation(boolean)
*/
public void setAutoCreateSessionAfterInvalidation(boolean autoCreate) {
assertSessionManager(AbstractValidatingSessionManager.class);
@@ -216,19 +217,19 @@
/**
* Passthrough configuration property that returns <code>true</code> if the wrapped
- * {@link AbstractValidatingSessionManager AbstractValidatingSessionManager} should automatically create a
+ * {@link org.apache.ki.session.mgt.AbstractValidatingSessionManager AbstractValidatingSessionManager} should automatically create a
* new session when an invalid session is referenced, <code>false</code> otherwise. Unless overridden by the
* {@link #setAutoCreateSessionAfterInvalidation(boolean)} method, the default value is <code>true</code> for
* developer convenience and to match what most people are accustomed based on years of servlet container behavior.
* <p/>
- * When true (the default), the wrapped {@link AbstractValidatingSessionManager AbstractValidatingSessionManager}
- * implementation throws an {@link org.ki.session.ReplacedSessionException ReplacedSessionException} to
+ * When true (the default), the wrapped {@link org.apache.ki.session.mgt.AbstractValidatingSessionManager AbstractValidatingSessionManager}
+ * implementation throws an {@link org.apache.ki.session.ReplacedSessionException ReplacedSessionException} to
* the caller whenever a new session is created so the caller can receive the new session ID and react accordingly
* for future {@link SessionManager SessionManager} method invocations.
*
* @return <code>true</code> if this session manager should automatically create a new session when an invalid
* session is referenced, <code>false</code> otherwise.
- * @see org.ki.session.mgt.AbstractValidatingSessionManager#isAutoCreateAfterInvalidation()
+ * @see org.apache.ki.session.mgt.AbstractValidatingSessionManager#isAutoCreateAfterInvalidation()
*/
public boolean isAutoCreateSessionAfterInvalidation() {
assertSessionManager(AbstractValidatingSessionManager.class);
@@ -237,7 +238,7 @@
/**
* Ensures the internal SessionManager instance is an <code>instanceof</code>
- * {@link org.ki.session.SessionListenerRegistrar SessionListenerRegistrar} to ensure that any
+ * {@link org.apache.ki.session.SessionListenerRegistrar SessionListenerRegistrar} to ensure that any
* listeners attempting to be registered can actually do so with the internal delegate instance.
*
* @throws IllegalStateException if the internal delegate SessionManager instance does not implement the
@@ -268,7 +269,7 @@
/**
* Removes the specified listener from receiving session events from the internal delegate
- * {@link SessionManager} instance.
+ * {@link org.apache.ki.session.mgt.SessionManager} instance.
*
* @param listener the listener to remove that no longer wishes to be notified of session events.
* @return <code>true</code> if the listener was removed from the internal delegate <code>SessionManager</code>
Copied: incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SubjectBinder.java (from r752240, incubator/jsecurity/trunk/core/src/org/ki/mgt/SubjectBinder.java)
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SubjectBinder.java?p2=incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SubjectBinder.java&p1=incubator/jsecurity/trunk/core/src/org/ki/mgt/SubjectBinder.java&r1=752240&r2=752380&rev=752380&view=diff
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/ki/mgt/SubjectBinder.java (original)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SubjectBinder.java Wed Mar 11 05:40:38 2009
@@ -16,9 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.ki.mgt;
+package org.apache.ki.mgt;
+
+import org.apache.ki.subject.Subject;
-import org.ki.subject.Subject;
/**
* TODO - Class JavaDoc
Copied: incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SubjectFactory.java (from r752240, incubator/jsecurity/trunk/core/src/org/ki/mgt/SubjectFactory.java)
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SubjectFactory.java?p2=incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SubjectFactory.java&p1=incubator/jsecurity/trunk/core/src/org/ki/mgt/SubjectFactory.java&r1=752240&r2=752380&rev=752380&view=diff
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/ki/mgt/SubjectFactory.java (original)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/SubjectFactory.java Wed Mar 11 05:40:38 2009
@@ -16,16 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.ki.mgt;
-
-import org.ki.authc.AuthenticationInfo;
-import org.ki.authc.AuthenticationToken;
-import org.ki.session.Session;
-import org.ki.subject.PrincipalCollection;
-import org.ki.subject.Subject;
+package org.apache.ki.mgt;
import java.net.InetAddress;
+import org.apache.ki.authc.AuthenticationInfo;
+import org.apache.ki.authc.AuthenticationToken;
+import org.apache.ki.session.Session;
+import org.apache.ki.subject.PrincipalCollection;
+import org.apache.ki.subject.Subject;
+
/**
* A {@code SubjectFactory} is responsible for returning {@link Subject Subject} instances as needed.
*
@@ -57,7 +57,7 @@
* @param principals the identifying attributes of the Subject instance to be created, or
* {@code null} if the Subject's identity is unknown because they haven't logged in yet and are not 'remembered'
* from {@code RememberMe} services.
- * @param existing any {@link Session Session} that might be in place for the specified {@link Subject}, or
+ * @param existing any {@link org.apache.ki.session.Session Session} that might be in place for the specified {@link org.apache.ki.subject.Subject}, or
* {@code null} if there is no session yet created for the specified {@code Subject}. If non-{@code null},
* it should be retained and used by the {@code Subject} instance returned from this method call.
* @param authenticated whether or not the {@code Subject} instance returned should be considered already
Copied: incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/ThreadContextSubjectBinder.java (from r752240, incubator/jsecurity/trunk/core/src/org/ki/mgt/ThreadContextSubjectBinder.java)
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/ThreadContextSubjectBinder.java?p2=incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/ThreadContextSubjectBinder.java&p1=incubator/jsecurity/trunk/core/src/org/ki/mgt/ThreadContextSubjectBinder.java&r1=752240&r2=752380&rev=752380&view=diff
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/ki/mgt/ThreadContextSubjectBinder.java (original)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/mgt/ThreadContextSubjectBinder.java Wed Mar 11 05:40:38 2009
@@ -16,12 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.ki.mgt;
+package org.apache.ki.mgt;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.ki.subject.Subject;
-import org.ki.util.ThreadContext;
+
+import org.apache.ki.subject.Subject;
+import org.apache.ki.util.ThreadContext;
+
/**
* Associates a {@link Subject Subject} instance to the currently executing thread via the {
@@ -29,7 +31,7 @@
* @author Les Hazlewood
* @link ThreadContext ThreadContext} to ensure that the <code>Subject</code> is accessible to any caller during
* thread execution.
- * @see org.ki.SecurityUtils#getSubject SecurityUtils.getSubject()
+ * @see org.apache.ki.SecurityUtils#getSubject SecurityUtils.getSubject()
* @since 1.0
*/
public class ThreadContextSubjectBinder implements SubjectBinder {
Added: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthenticatingRealm.java
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthenticatingRealm.java?rev=752380&view=auto
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthenticatingRealm.java (added)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthenticatingRealm.java Wed Mar 11 05:40:38 2009
@@ -0,0 +1,243 @@
+/*
+ * 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.ki.realm;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.ki.authc.AuthenticationException;
+import org.apache.ki.authc.AuthenticationInfo;
+import org.apache.ki.authc.AuthenticationToken;
+import org.apache.ki.authc.IncorrectCredentialsException;
+import org.apache.ki.authc.LogoutAware;
+import org.apache.ki.authc.UsernamePasswordToken;
+import org.apache.ki.authc.credential.AllowAllCredentialsMatcher;
+import org.apache.ki.authc.credential.CredentialsMatcher;
+import org.apache.ki.authc.credential.SimpleCredentialsMatcher;
+import org.apache.ki.cache.CacheManager;
+import org.apache.ki.subject.PrincipalCollection;
+
+
+/**
+ * A top-level abstract implementation of the <tt>Realm</tt> interface that only implements authentication support
+ * (log-in) operations and leaves authorization (access control) behavior to subclasses.
+ *
+ * <p>Since a Realm provides both authentication <em>and</em> authorization operations, the implementation approach for
+ * this class could have been reversed. That is, authorization support could have been implemented here and
+ * authentication support left to subclasses.
+ *
+ * <p>The reason the existing implementation is in place though
+ * (authentication support) is that most authentication operations are fairly common across the large majority of
+ * applications, whereas authorization operations are more so heavily dependent upon the application's data model, which
+ * can vary widely.
+ *
+ * <p>By providing the most common authentication operations here and leaving data-model specific authorization checks
+ * to subclasses, a top-level abstract class for most common authentication behavior is more useful as an extension
+ * point for most applications.
+ *
+ * @author Les Hazlewood
+ * @author Jeremy Haile
+ * @since 0.2
+ */
+public abstract class AuthenticatingRealm extends CachingRealm implements LogoutAware {
+
+ //TODO - complete JavaDoc
+
+ private static final Log log = LogFactory.getLog(AuthenticatingRealm.class);
+
+ /**
+ * Password matcher used to determine if the provided password matches
+ * the password stored in the data store.
+ */
+ private CredentialsMatcher credentialsMatcher = new SimpleCredentialsMatcher();
+
+ /**
+ * The class that this realm supports for authentication tokens. This is used by the
+ * default implementation of the {@link Realm#supports(org.apache.ki.authc.AuthenticationToken)} method to
+ * determine whether or not the given authentication token is supported by this realm.
+ */
+ private Class<? extends AuthenticationToken> authenticationTokenClass = UsernamePasswordToken.class;
+
+ /*--------------------------------------------
+ | C O N S T R U C T O R S |
+ ============================================*/
+ public AuthenticatingRealm() {
+ }
+
+ public AuthenticatingRealm(CacheManager cacheManager) {
+ setCacheManager(cacheManager);
+ }
+
+ public AuthenticatingRealm(CredentialsMatcher matcher) {
+ setCredentialsMatcher(matcher);
+ }
+
+ public AuthenticatingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
+ setCacheManager(cacheManager);
+ setCredentialsMatcher(matcher);
+ }
+
+ /*--------------------------------------------
+ | A C C E S S O R S / M O D I F I E R S |
+ ============================================*/
+ /**
+ * Returns the <code>CredentialsMatcher</code> used during an authentication attempt to verify submitted
+ * credentials with those stored in the system.
+ *
+ * <p>Unless overridden by the {@link #setCredentialsMatcher setCredentialsMatcher} method, the default
+ * value is a {@link org.apache.ki.authc.credential.SimpleCredentialsMatcher SimpleCredentialsMatcher} instance.
+ *
+ * @return the <code>CredentialsMatcher</code> used during an authentication attempt to verify submitted
+ * credentials with those stored in the system.
+ */
+ public CredentialsMatcher getCredentialsMatcher() {
+ return credentialsMatcher;
+ }
+
+ /**
+ * Sets the CrendialsMatcher used during an authentication attempt to verify submitted credentials with those
+ * stored in the system. The implementation of this matcher can be switched via configuration to
+ * support any number of schemes, including plain text comparisons, hashing comparisons, and others.
+ *
+ * <p>Unless overridden by this method, the default value is a
+ * {@link org.apache.ki.authc.credential.SimpleCredentialsMatcher} instance.
+ *
+ * @param credentialsMatcher the matcher to use.
+ */
+ public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
+ this.credentialsMatcher = credentialsMatcher;
+ }
+
+ /**
+ * Returns the authenticationToken class supported by this realm.
+ *
+ * <p>The default value is <tt>{@link org.apache.ki.authc.UsernamePasswordToken UsernamePasswordToken.class}</tt>, since
+ * about 90% of realms use username/password authentication, regardless of their protocol (e.g. over jdbc, ldap,
+ * kerberos, http, etc).
+ *
+ * <p>If subclasses haven't already overridden the {@link Realm#supports Realm.supports(AuthenticationToken)} method,
+ * they must {@link #setAuthenticationTokenClass(Class) set a new class} if they won't support
+ * <tt>UsernamePasswordToken</tt> authentication token submissions.
+ *
+ * @return the authenticationToken class supported by this realm.
+ * @see #setAuthenticationTokenClass
+ */
+ public Class getAuthenticationTokenClass() {
+ return authenticationTokenClass;
+ }
+
+ /**
+ * Sets the authenticationToken class supported by this realm.
+ *
+ * <p>Unless overridden by this method, the default value is
+ * {@link org.apache.ki.authc.UsernamePasswordToken UsernamePasswordToken.class} to support the majority of applications.
+ *
+ * @param authenticationTokenClass the class of authentication token instances supported by this realm.
+ * @see #getAuthenticationTokenClass getAuthenticationTokenClass() for more explanation.
+ */
+ public void setAuthenticationTokenClass(Class<? extends AuthenticationToken> authenticationTokenClass) {
+ this.authenticationTokenClass = authenticationTokenClass;
+ }
+
+ /*--------------------------------------------
+ | M E T H O D S |
+ ============================================*/
+ /**
+ * Convenience implementation that returns
+ * <tt>getAuthenticationTokenClass().isAssignableFrom( token.getClass() );</tt>. Can be overridden
+ * by subclasses for more complex token checking.
+ * <p>Most configurations will only need to set a different class via
+ * {@link #setAuthenticationTokenClass}, as opposed to overriding this method.
+ *
+ * @param token the token being submitted for authentication.
+ * @return true if this authentication realm can process the submitted token instance of the class, false otherwise.
+ */
+ public boolean supports(AuthenticationToken token) {
+ return token != null && getAuthenticationTokenClass().isAssignableFrom(token.getClass());
+ }
+
+ public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+
+ AuthenticationInfo info = doGetAuthenticationInfo(token);
+
+ if (info == null) {
+ if (log.isDebugEnabled()) {
+ String msg = "No authentication information found for submitted authentication token [" + token + "]. " +
+ "Returning null.";
+ log.debug(msg);
+ }
+ return null;
+ }
+
+ CredentialsMatcher cm = getCredentialsMatcher();
+ if (cm != null) {
+ if (!cm.doCredentialsMatch(token, info)) {
+ String msg = "The credentials provided for account [" + token +
+ "] did not match the expected credentials.";
+ throw new IncorrectCredentialsException(msg);
+ }
+ } else {
+ throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
+ "credentials during authentication. If you do not wish for credentials to be examined, you " +
+ "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
+ }
+
+ return info;
+ }
+
+ /**
+ * Retrieves authentication data from an implementation-specific datasource (RDBMS, LDAP, etc) for the given
+ * authentication token.
+ *
+ * <p>For most datasources, this means just 'pulling' authentication data for an associated subject/user and nothing
+ * more and letting JSecurity do the rest. But in some systems, this method could actually perform EIS specific
+ * log-in logic in addition to just retrieving data - it is up to the Realm implementation.
+ *
+ * <p>A <tt>null</tt> return value means that no account could be associated with the specified token.
+ *
+ * @param token the authentication token containing the user's principal and credentials.
+ * @return an {@link AuthenticationInfo} object containing account data resulting from the
+ * authentication ONLY if the lookup is successful (i.e. account exists and is valid, etc.)
+ * @throws org.apache.ki.authc.AuthenticationException
+ * if there is an error acquiring data or performing
+ * realm-specific authentication logic for the specified <tt>token</tt>
+ */
+ protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
+
+ /**
+ * Default implementation that does nothing (no-op) and exists as a convenience mechanism in case subclasses
+ * wish to override it to implement realm-specific logout logic for the given user account logging out.</p>
+ * <p/>
+ * In a single-realm JSecurity configuration (most applications), the <code>principals</code> method
+ * argument will be the same as that which is contained in the <code>AuthenticationInfo</code> object returned by the
+ * {@link #doGetAuthenticationInfo} method (that is, {@link AuthenticationInfo#getPrincipals info.getPrincipals()}).
+ * <p/>
+ * In a multi-realm JSecurity configuration, the given <code>principals</code> method
+ * argument could contain principals returned by many realms. Therefore the subclass implementation would need
+ * to know how to extract the principal(s) relevant to only itself and ignore other realms' principals. This is
+ * usually done by calling {@link org.apache.ki.subject.PrincipalCollection#fromRealm(String) principals.fromRealm(name)},
+ * using the realm's own {@link Realm#getName() name}.
+ *
+ * @param principals the application-specific Subject/user identifier that is logging out.
+ */
+ public void onLogout(PrincipalCollection principals) {
+ //no-op, here for subclass override if desired.
+ }
+
+}
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthenticatingRealm.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthenticatingRealm.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Id Author
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthenticatingRealm.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthorizingRealm.java
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthorizingRealm.java?rev=752380&view=auto
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthorizingRealm.java (added)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthorizingRealm.java Wed Mar 11 05:40:38 2009
@@ -0,0 +1,630 @@
+/*
+ * 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.ki.realm;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.ki.authc.credential.CredentialsMatcher;
+import org.apache.ki.authz.AuthorizationException;
+import org.apache.ki.authz.AuthorizationInfo;
+import org.apache.ki.authz.AuthorizingAccount;
+import org.apache.ki.authz.Permission;
+import org.apache.ki.authz.UnauthorizedException;
+import org.apache.ki.authz.permission.PermissionResolver;
+import org.apache.ki.authz.permission.PermissionResolverAware;
+import org.apache.ki.authz.permission.WildcardPermissionResolver;
+import org.apache.ki.cache.Cache;
+import org.apache.ki.cache.CacheManager;
+import org.apache.ki.subject.PrincipalCollection;
+import org.apache.ki.util.Initializable;
+
+
+/**
+ * An <tt>AuthorizingRealm</tt> extends the <tt>AuthenticatingRealm</tt>'s capabilities by adding Authorization
+ * (access control) support.
+ *
+ * <p>This implementation will perform all role and permission checks automatically (and subclasses do not have to
+ * write this logic) as long as the
+ * {@link #getAuthorizationInfo(org.apache.ki.subject.PrincipalCollection)} method returns an
+ * {@link AuthorizationInfo}. Please see that method's JavaDoc for an in-depth explanation.
+ *
+ * <p>If you find that you do not want to utilize the {@link AuthorizationInfo AuthorizationInfo} construct,
+ * you are of course free to subclass the {@link AuthenticatingRealm AuthenticatingRealm} directly instead and
+ * implement the remaining Realm interface methods directly. You might do this if you want have better control
+ * over how the Role and Permission checks occur for your specific data source. However, using AuthorizationInfo
+ * (and its default implementation {@link org.apache.ki.authz.SimpleAuthorizationInfo SimpleAuthorizationInfo}) is sufficient in the large
+ * majority of Realm cases.
+ *
+ * @author Les Hazlewood
+ * @author Jeremy Haile
+ * @see org.apache.ki.authz.SimpleAuthorizationInfo
+ * @since 0.2
+ */
+public abstract class AuthorizingRealm extends AuthenticatingRealm implements Initializable, PermissionResolverAware {
+
+ //TODO - complete JavaDoc
+
+ /*--------------------------------------------
+ | C O N S T A N T S |
+ ============================================*/
+ private static final Log log = LogFactory.getLog(AuthorizingRealm.class);
+
+ /**
+ * The default postfix appended to the realm name for caching AuthorizationInfos.
+ */
+ private static final String DEFAULT_AUTHORIZATION_CACHE_POSTFIX = "-authorization";
+
+ private static int INSTANCE_COUNT = 0;
+
+ /*--------------------------------------------
+ | I N S T A N C E V A R I A B L E S |
+ ============================================*/
+ /**
+ * The cache used by this realm to store AuthorizationInfos associated with individual Subject principals.
+ */
+ private Cache authorizationCache = null;
+ private String authorizationCacheName = null;
+
+ private PermissionResolver permissionResolver = new WildcardPermissionResolver();
+
+ /*--------------------------------------------
+ | C O N S T R U C T O R S |
+ ============================================*/
+ public AuthorizingRealm() {
+ }
+
+ public AuthorizingRealm(CacheManager cacheManager) {
+ super(cacheManager);
+ }
+
+ public AuthorizingRealm(CredentialsMatcher matcher) {
+ super(matcher);
+ }
+
+ public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
+ super(cacheManager, matcher);
+ }
+
+ /*--------------------------------------------
+ | A C C E S S O R S / M O D I F I E R S |
+ ============================================*/
+ public void setAuthorizationCache(Cache authorizationCache) {
+ this.authorizationCache = authorizationCache;
+ if (this.authorizationCache != null) {
+ afterAuthorizationCacheSet();
+ }
+ }
+
+ public Cache getAuthorizationCache() {
+ return this.authorizationCache;
+ }
+
+ public String getAuthorizationCacheName() {
+ return authorizationCacheName;
+ }
+
+ public void setAuthorizationCacheName(String authorizationCacheName) {
+ this.authorizationCacheName = authorizationCacheName;
+ }
+
+ public PermissionResolver getPermissionResolver() {
+ return permissionResolver;
+ }
+
+ public void setPermissionResolver(PermissionResolver permissionResolver) {
+ this.permissionResolver = permissionResolver;
+ }
+
+ /*--------------------------------------------
+ | M E T H O D S |
+ ============================================*/
+ /**
+ * Initializes this realm and potentially enables a cache, depending on configuration.
+ *
+ * <p>When this method is called, the following logic is executed:
+ * <ol>
+ * <li>If the {@link #setAuthorizationCache cache} property has been set, it will be
+ * used to cache the AuthorizationInfo objects returned from {@link #getAuthorizationInfo}
+ * method invocations.
+ * All future calls to <tt>getAuthorizationInfo</tt> will attempt to use this cache first
+ * to alleviate any potentially unnecessary calls to an underlying data store.</li>
+ * <li>If the {@link #setAuthorizationCache cache} property has <b>not</b> been set,
+ * the {@link #setCacheManager cacheManager} property will be checked.
+ * If a <tt>cacheManager</tt> has been set, it will be used to create an authorization
+ * <tt>cache</tt>, and this newly created cache which will be used as specified in #1.</li>
+ * <li>If neither the {@link #setAuthorizationCache (org.jsecurity.cache.Cache) cache}
+ * or {@link #setCacheManager(org.apache.ki.cache.CacheManager) cacheManager}
+ * properties are set, caching will be disabled and authorization lookups will be delegated to
+ * subclass implementations for each authorization check.</li>
+ * </ol>
+ */
+ public final void init() {
+ initAuthorizationCache();
+ }
+
+ protected void afterCacheManagerSet() {
+ this.authorizationCache = null;
+ initAuthorizationCache();
+ }
+
+ protected void afterAuthorizationCacheSet() {
+ }
+
+ public void initAuthorizationCache() {
+ if (log.isTraceEnabled()) {
+ log.trace("Initializing authorization cache.");
+ }
+
+ Cache cache = getAuthorizationCache();
+
+ if (cache == null) {
+
+ if (log.isDebugEnabled()) {
+ log.debug("No cache implementation set. Checking cacheManager...");
+ }
+
+ CacheManager cacheManager = getCacheManager();
+
+ if (cacheManager != null) {
+ String cacheName = getAuthorizationCacheName();
+ if (cacheName == null) {
+ //Simple default in case they didn't provide one:
+ cacheName = getClass().getName() + "-" + INSTANCE_COUNT++ + DEFAULT_AUTHORIZATION_CACHE_POSTFIX;
+ setAuthorizationCacheName(cacheName);
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("CacheManager [" + cacheManager + "] has been configured. Building " +
+ "authorization cache named [" + cacheName + "]");
+ }
+ cache = cacheManager.getCache(cacheName);
+ setAuthorizationCache(cache);
+ } else {
+ if (log.isInfoEnabled()) {
+ log.info("No cache or cacheManager properties have been set. Authorization caching is " +
+ "disabled.");
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Returns an account's authorization-specific information for the specified <code>principals</code>,
+ * or <tt>null</tt> if no account could be found. The resulting <code>AuthorizationInfo</code> object is used
+ * by the other method implementations in this class to automatically perform access control checks for the
+ * corresponding <code>Subject</code>.
+ *
+ * <p>This implementation obtains the actual <code>AuthorizationInfo</code> object from the subclass's
+ * implementation of
+ * {@link #doGetAuthorizationInfo(org.apache.ki.subject.PrincipalCollection) doGetAuthorizationInfo}, and then
+ * caches it for efficient reuse if caching is enabled (see below).
+ *
+ * <p>Invocations of this method should be thought of as completely orthogonal to acquiring
+ * {@link #getAuthenticationInfo(org.apache.ki.authc.AuthenticationToken) authenticationInfo}, since either could
+ * occur in any order.
+ *
+ * <p>For example, in "Remember Me" scenarios, the user identity is remembered (and
+ * assumed) for their current session and an authentication attempt during that session might never occur.
+ * But because their identity would be remembered, that is sufficient enough information to call this method to
+ * execute any necessary authorization checks. For this reason, authentication and authorization should be
+ * loosely coupled and not depend on each other.
+ *
+ * <h4>Caching</h4>
+ *
+ * <p>The <code>AuthorizationInfo</code> values returned from this method are cached for performant reuse
+ * if caching is enabled. Caching is enabled automatically when a <code>CacheManager</code> has been
+ * {@link #setCacheManager injected} and then the realm is {@link #init initialized}. It can also be enabled by explictly
+ * calling {@link #initAuthorizationCache() initAuthorizationCache()}.
+ *
+ * <p>If caching is enabled, the authorization cache will be checked first and if found, will return the cached
+ * <code>AuthorizationInfo</code> immediately. If caching is disabled, or there is a cache miss from the cache
+ * lookup, the authorization info will be looked up from the underlying data store via the
+ * {@link #doGetAuthorizationInfo(org.apache.ki.subject.PrincipalCollection)} method, which must be implemented by subclasses.
+ *
+ * <p><b>Please note:</b> If caching is enabled and if any authorization data for an account is changed at
+ * runtime, such as adding or removing roles and/or permissions, the subclass imlementation should clear the
+ * cached AuthorizationInfo for that account via the
+ * {@link #clearCachedAuthorizationInfo(org.apache.ki.subject.PrincipalCollection) clearCachedAuthorizationInfo}
+ * method. This ensures that the next call to <code>getAuthorizationInfo(PrincipalCollection)</code> will
+ * acquire the account's fresh authorization data, where it will then be cached for efficient reuse. This
+ * ensures that stale authorization data will not be reused.
+ *
+ * @param principals the corresponding Subject's identifying principals with which to look up the Subject's
+ * <code>AuthorizationInfo</code>.
+ * @return the authorization information for the account associated with the specified <code>principals</code>,
+ * or <tt>null</tt> if no account could be found.
+ */
+ public AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
+
+ if (principals == null) {
+ return null;
+ }
+
+ AuthorizationInfo info = null;
+
+ if (log.isTraceEnabled()) {
+ log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");
+ }
+
+ Cache authzCache = getAuthorizationCache();
+ if (authzCache != null) {
+ if (log.isTraceEnabled()) {
+ log.trace("Attempting to retrieve the AuthorizationIfno from cache.");
+ }
+ Object key = getAuthorizationCacheKey(principals);
+ info = (AuthorizationInfo) authzCache.get(key);
+ if (log.isTraceEnabled()) {
+ if (info == null) {
+ log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");
+ } else {
+ log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");
+ }
+ }
+ }
+
+
+ if (info == null) {
+ // Call template method if tbe info was not found in a cache
+ info = doGetAuthorizationInfo(principals);
+ // If the info is not null and the cache has been created, then cache the authorization info.
+ if (info != null && authzCache != null) {
+ if (log.isTraceEnabled()) {
+ log.trace("Caching authorization info for principals: [" + principals + "].");
+ }
+ Object key = getAuthorizationCacheKey(principals);
+ authzCache.put(key, info);
+ }
+ }
+
+ return info;
+ }
+
+ protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
+ return principals;
+ }
+
+ /**
+ * Clears out the AuthorizationInfo cache entry for the specified account.
+ * <p/>
+ * This method is provided as a convenience to subclasses so they can invalidate a cache entry when they
+ * change an account's authorization data (add/remove roles or permissions) during runtime. Because an account's
+ * AuthorizationInfo can be cached, there needs to be a way to invalidate the cache for only that account so that
+ * subsequent authorization operations don't used the (old) cached value if account data changes.
+ * <p/>
+ * After this method is called, the next authorization check for that same account will result in a call to
+ * {@link #getAuthorizationInfo(org.apache.ki.subject.PrincipalCollection) getAuthorizationInfo}, and the
+ * resulting return value will be cached before being returned so it can be reused for later authorization checks.
+ *
+ * @param principals the principals of the account for which to clear the cached AuthorizationInfo.
+ */
+ protected void clearCachedAuthorizationInfo(PrincipalCollection principals) {
+ if ( principals == null ) {
+ return;
+ }
+
+ Cache cache = getAuthorizationCache();
+ //cache instance will be non-null if caching is enabled:
+ if (cache != null) {
+ Object key = getAuthorizationCacheKey(principals);
+ cache.remove(key);
+ }
+ }
+
+ /**
+ * Retrieves the AuthorizationInfo for the given principals from the underlying data store. When returning
+ * an instance from this method, you might want to consider using an instance of
+ * {@link org.apache.ki.authz.SimpleAuthorizationInfo SimpleAuthorizationInfo}, as it is suitable in most cases.
+ *
+ * @param principals the primary identifying principals of the AuthorizationInfo that should be retrieved.
+ * @return the AuthorizationInfo associated with this principals.
+ * @see org.apache.ki.authz.SimpleAuthorizationInfo
+ */
+ protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals);
+
+ @SuppressWarnings({"unchecked"})
+ private Collection<Permission> getPermissions(AuthorizationInfo info) {
+ Set<Permission> permissions = new HashSet<Permission>();
+
+ if (info != null) {
+ if (info.getObjectPermissions() != null) {
+ permissions.addAll(info.getObjectPermissions());
+ }
+
+ if (info.getStringPermissions() != null) {
+ for (String strPermission : info.getStringPermissions()) {
+ Permission permission = getPermissionResolver().resolvePermission(strPermission);
+ permissions.add(permission);
+ }
+ }
+ }
+
+ if (permissions.isEmpty()) {
+ return Collections.EMPTY_SET;
+ } else {
+ return Collections.unmodifiableSet(permissions);
+ }
+ }
+
+ public boolean isPermitted(PrincipalCollection principals, String permission) {
+ Permission p = getPermissionResolver().resolvePermission(permission);
+ return isPermitted(principals, p);
+ }
+
+ public boolean isPermitted(PrincipalCollection principals, Permission permission) {
+ AuthorizationInfo info = getAuthorizationInfo(principals);
+ return isPermitted(permission, info);
+ }
+
+ @SuppressWarnings("deprecation")
+ private boolean isPermitted(Permission permission, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ return ((AuthorizingAccount) info).isPermitted(permission);
+ }
+
+ Collection<Permission> perms = getPermissions(info);
+ if (perms != null && !perms.isEmpty()) {
+ for (Permission perm : perms) {
+ if (perm.implies(permission)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean[] isPermitted(PrincipalCollection subjectIdentifier, String... permissions) {
+ List<Permission> perms = new ArrayList<Permission>(permissions.length);
+ for (String permString : permissions) {
+ perms.add(getPermissionResolver().resolvePermission(permString));
+ }
+ return isPermitted(subjectIdentifier, perms);
+ }
+
+ public boolean[] isPermitted(PrincipalCollection principals, List<Permission> permissions) {
+ AuthorizationInfo info = getAuthorizationInfo(principals);
+ return isPermitted(permissions, info);
+ }
+
+ @SuppressWarnings("deprecation")
+ protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ return ((AuthorizingAccount) info).isPermitted(permissions);
+ }
+
+ boolean[] result;
+ if (permissions != null && !permissions.isEmpty()) {
+ int size = permissions.size();
+ result = new boolean[size];
+ int i = 0;
+ for (Permission p : permissions) {
+ result[i++] = isPermitted(p, info);
+ }
+ } else {
+ result = new boolean[0];
+ }
+ return result;
+ }
+
+ public boolean isPermittedAll(PrincipalCollection subjectIdentifier, String... permissions) {
+ if (permissions != null && permissions.length > 0) {
+ Collection<Permission> perms = new ArrayList<Permission>(permissions.length);
+ for (String permString : permissions) {
+ perms.add(getPermissionResolver().resolvePermission(permString));
+ }
+ return isPermittedAll(subjectIdentifier, perms);
+ }
+ return false;
+ }
+
+ public boolean isPermittedAll(PrincipalCollection principal, Collection<Permission> permissions) {
+ AuthorizationInfo info = getAuthorizationInfo(principal);
+ return info != null && isPermittedAll(permissions, info);
+ }
+
+ @SuppressWarnings("deprecation")
+ protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ return ((AuthorizingAccount) info).isPermittedAll(permissions);
+ }
+
+ if (permissions != null && !permissions.isEmpty()) {
+ for (Permission p : permissions) {
+ if (!isPermitted(p, info)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public void checkPermission(PrincipalCollection subjectIdentifier, String permission) throws AuthorizationException {
+ Permission p = getPermissionResolver().resolvePermission(permission);
+ checkPermission(subjectIdentifier, p);
+ }
+
+ public void checkPermission(PrincipalCollection principal, Permission permission) throws AuthorizationException {
+ AuthorizationInfo info = getAuthorizationInfo(principal);
+ checkPermission(permission, info);
+ }
+
+ @SuppressWarnings("deprecation")
+ protected void checkPermission(Permission permission, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ ((AuthorizingAccount) info).checkPermission(permission);
+ } else {
+ if (!isPermitted(permission, info)) {
+ String msg = "User is not permitted [" + permission + "]";
+ throw new UnauthorizedException(msg);
+ }
+ }
+ }
+
+ public void checkPermissions(PrincipalCollection subjectIdentifier, String... permissions) throws AuthorizationException {
+ if (permissions != null) {
+ for (String permString : permissions) {
+ checkPermission(subjectIdentifier, permString);
+ }
+ }
+ }
+
+ public void checkPermissions(PrincipalCollection principal, Collection<Permission> permissions) throws AuthorizationException {
+ AuthorizationInfo info = getAuthorizationInfo(principal);
+ checkPermissions(permissions, info);
+ }
+
+ @SuppressWarnings("deprecation")
+ protected void checkPermissions(Collection<Permission> permissions, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ ((AuthorizingAccount) info).checkPermissions(permissions);
+ } else {
+ if (permissions != null && !permissions.isEmpty()) {
+ for (Permission p : permissions) {
+ checkPermission(p, info);
+ }
+ }
+ }
+ }
+
+ public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {
+ AuthorizationInfo info = getAuthorizationInfo(principal);
+ return hasRole(roleIdentifier, info);
+ }
+
+ @SuppressWarnings("deprecation")
+ protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ return ((AuthorizingAccount) info).hasRole(roleIdentifier);
+ }
+ return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
+ }
+
+ public boolean[] hasRoles(PrincipalCollection principal, List<String> roleIdentifiers) {
+ AuthorizationInfo info = getAuthorizationInfo(principal);
+ boolean[] result = new boolean[roleIdentifiers != null ? roleIdentifiers.size() : 0];
+ if (info != null) {
+ result = hasRoles(roleIdentifiers, info);
+ }
+ return result;
+ }
+
+ @SuppressWarnings("deprecation")
+ protected boolean[] hasRoles(List<String> roleIdentifiers, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ return ((AuthorizingAccount) info).hasRoles(roleIdentifiers);
+ }
+
+ boolean[] result;
+ if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) {
+ int size = roleIdentifiers.size();
+ result = new boolean[size];
+ int i = 0;
+ for (String roleName : roleIdentifiers) {
+ result[i++] = hasRole(roleName, info);
+ }
+ } else {
+ result = new boolean[0];
+ }
+ return result;
+ }
+
+ public boolean hasAllRoles(PrincipalCollection principal, Collection<String> roleIdentifiers) {
+ AuthorizationInfo info = getAuthorizationInfo(principal);
+ return info != null && hasAllRoles(roleIdentifiers, info);
+ }
+
+ @SuppressWarnings("deprecation")
+ private boolean hasAllRoles(Collection<String> roleIdentifiers, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ return ((AuthorizingAccount) info).hasAllRoles(roleIdentifiers);
+ }
+
+ if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) {
+ for (String roleName : roleIdentifiers) {
+ if (!hasRole(roleName, info)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public void checkRole(PrincipalCollection principal, String role) throws AuthorizationException {
+ AuthorizationInfo info = getAuthorizationInfo(principal);
+ checkRole(role, info);
+ }
+
+ @SuppressWarnings("deprecation")
+ protected void checkRole(String role, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ ((AuthorizingAccount) info).checkRole(role);
+ } else {
+ if (!hasRole(role, info)) {
+ String msg = "User does not have role [" + role + "]";
+ throw new UnauthorizedException(msg);
+ }
+ }
+ }
+
+ public void checkRoles(PrincipalCollection principal, Collection<String> roles) throws AuthorizationException {
+ AuthorizationInfo info = getAuthorizationInfo(principal);
+ checkRoles(roles, info);
+ }
+
+ @SuppressWarnings("deprecation")
+ protected void checkRoles(Collection<String> roles, AuthorizationInfo info) {
+ //todo Remove this once AuthorizingAccount class is deleted
+ if (info instanceof AuthorizingAccount) {
+ ((AuthorizingAccount) info).checkRoles(roles);
+ } else {
+ if (roles != null && !roles.isEmpty()) {
+ for (String roleName : roles) {
+ checkRole(roleName, info);
+ }
+ }
+ }
+ }
+
+ /**
+ * If authorization caching is enabled, this will remove the AuthorizationInfo from the cache.
+ * Subclasses are free to override for additional behavior, but be sure to call <tt>super.onLogout</tt>
+ * to ensure cache cleanup.
+ *
+ * @param principals the application-specific Subject/user identifier.
+ */
+ public void onLogout(PrincipalCollection principals) {
+ clearCachedAuthorizationInfo(principals);
+ }
+}
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthorizingRealm.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthorizingRealm.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Id Author
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/AuthorizingRealm.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/CachingRealm.java
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/realm/CachingRealm.java?rev=752380&view=auto
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/apache/ki/realm/CachingRealm.java (added)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/realm/CachingRealm.java Wed Mar 11 05:40:38 2009
@@ -0,0 +1,86 @@
+/*
+ * 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.ki.realm;
+
+import org.apache.ki.cache.CacheManager;
+import org.apache.ki.cache.CacheManagerAware;
+
+
+/**
+ * <p>A very basic abstract extension point for the {@link Realm} interface that provides logging and caching support.
+ *
+ * <p>All actual Realm method implementations are left to subclasses.
+ *
+ * @author Les Hazlewood
+ * @since 0.9
+ */
+public abstract class CachingRealm implements Realm, CacheManagerAware {
+
+ //TODO - complete JavaDoc
+
+ private static int INSTANCE_COUNT = 0;
+
+ /*--------------------------------------------
+ | I N S T A N C E V A R I A B L E S |
+ ============================================*/
+ private String name = getClass().getName() + "_" + INSTANCE_COUNT++;
+
+ private CacheManager cacheManager;
+
+ public CachingRealm() {
+ }
+
+ public CachingRealm(CacheManager cacheManager) {
+ setCacheManager(cacheManager);
+ }
+
+ /**
+ * Returns the <tt>CacheManager</tt> used for data caching to reduce EIS round trips, or <tt>null</tt> if
+ * caching is disabled.
+ *
+ * @return the <tt>CacheManager</tt> used for data caching to reduce EIS round trips, or <tt>null</tt> if
+ * caching is disabled.
+ */
+ public CacheManager getCacheManager() {
+ return this.cacheManager;
+ }
+
+ /**
+ * Sets the <tt>CacheManager</tt> to be used for data caching to reduce EIS round trips.
+ *
+ * <p>This property is <tt>null</tt> by default, indicating that caching is turned off.
+ *
+ * @param authzInfoCacheManager the <tt>CacheManager</tt> to use for data caching, or <tt>null</tt> to disable caching.
+ */
+ public void setCacheManager(CacheManager authzInfoCacheManager) {
+ this.cacheManager = authzInfoCacheManager;
+ afterCacheManagerSet();
+ }
+
+ protected void afterCacheManagerSet() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/CachingRealm.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/CachingRealm.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Id Author
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/CachingRealm.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/Realm.java
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/realm/Realm.java?rev=752380&view=auto
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/apache/ki/realm/Realm.java (added)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/realm/Realm.java Wed Mar 11 05:40:38 2009
@@ -0,0 +1,109 @@
+/*
+ * 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.ki.realm;
+
+import org.apache.ki.authc.AuthenticationException;
+import org.apache.ki.authc.AuthenticationInfo;
+import org.apache.ki.authc.AuthenticationToken;
+import org.apache.ki.authz.Authorizer;
+
+
+/**
+ * A <tt>Realm</tt> is a security component that can access application-specific security entities
+ * such as users, roles, and permissions to determine authentication and authorization operations.
+ *
+ * <p><tt>Realm</tt>s usually have a 1-to-1 correspondance with a datasource such as a relational database,
+ * file sysetem, or other similar resource. As such, implementations of this interface use datasource-specific APIs to
+ * determine authorization data (roles, permissions, etc), such as JDBC, File IO, Hibernate or JPA, or any other
+ * Data Access API. They are essentially security-specific
+ * <a href="http://en.wikipedia.org/wiki/Data_Access_Object" target="_blank">DAO</a>s.
+ *
+ * <p>Because most of these datasources usually contain Subject (a.k.a. User) information such as usernames and
+ * passwords, a Realm can act as a pluggable authentication module in a
+ * <a href="http://en.wikipedia.org/wiki/Pluggable_Authentication_Modules">PAM</a> configuration. This allows a Realm to
+ * perform <i>both</i> authentication and authorization duties for a single datasource, which caters to the large
+ * majority of applications. If for some reason you don't want your Realm implementation to perform authentication
+ * duties, you should override the {@link #supports(org.apache.ki.authc.AuthenticationToken)} method to always
+ * return <tt>false</tt>.
+ *
+ * <p>Because every application is different, security data such as users and roles can be
+ * represented in any number of ways. JSecurity tries to maintain a non-intrusive development philosophy whenever
+ * possible - it does not require you to implement or extend any <tt>User</tt>, <tt>Group</tt> or <tt>Role</tt>
+ * interfaces or classes.
+ *
+ * <p>Instead, JSecurity allows applications to implement this interface to access environment-specific datasources
+ * and data model objects. The implementation can then be plugged in to the application's JSecurity configuration.
+ * This modular technique abstracts away any environment/modeling details and allows JSecurity to be deployed in
+ * practically any application environment.
+ *
+ * <p>Most users will not implement the <tt>Realm</tt> interface directly, but will extend one of the subclasses,
+ * {@link org.apache.ki.realm.AuthenticatingRealm AuthenticatingRealm} or {@link org.apache.ki.realm.AuthorizingRealm}, greatly reducing the effort requird
+ * to implement a <tt>Realm</tt> from scratch.</p>
+ *
+ * @author Les Hazlewood
+ * @author Jeremy Haile
+ * @see org.apache.ki.realm.CachingRealm CachingRealm
+ * @see org.apache.ki.realm.AuthenticatingRealm AuthenticatingRealm
+ * @see org.apache.ki.realm.AuthorizingRealm AuthorizingRealm
+ * @see org.apache.ki.authc.pam.ModularRealmAuthenticator ModularRealmAuthenticator
+ * @since 0.1
+ */
+public interface Realm extends Authorizer {
+
+ /**
+ * Returns the (application-unique) name assigned to this <code>Realm</code>. All realms configured for a single
+ * application must have a unique name.
+ *
+ * @return the (application-unique) name assigned to this <code>Realm</code>.
+ */
+ String getName();
+
+ /**
+ * Returns <tt>true</tt> if this realm wishes to authenticate the Subject represented by the given
+ * {@link org.apache.ki.authc.AuthenticationToken AuthenticationToken} instance, <tt>false</tt> otherwise.
+ *
+ * <p>If this method returns <tt>false</tt>, it will not be called to authenticate the Subject represented by
+ * the token - more specifically, a <tt>false</tt> return value means this Realm instance's
+ * {@link #getAuthenticationInfo} method will not be invoked for that token.
+ *
+ * @param token the AuthenticationToken submitted for the authentication attempt
+ * @return <tt>true</tt> if this realm can/will authenticate Subjects represented by specified token,
+ * <tt>false</tt> otherwise.
+ */
+ boolean supports(AuthenticationToken token);
+
+ /**
+ * Returns an account's authentication-specific information for the specified <tt>token</tt>,
+ * or <tt>null</tt> if no account could be found based on the <tt>token</tt>.
+ *
+ * <p>This method effectively represents a login attempt for the corresponding user with the underlying EIS datasource.
+ * Most implementations merely just need to lookup and return the account data only (as the method name implies)
+ * and let JSecurity do the rest, but implementations may of course perform eis specific login operations if so
+ * desired.
+ *
+ * @param token the application-specific representation of an account principal and credentials.
+ * @return the authentication information for the account associated with the specified <tt>token</tt>,
+ * or <tt>null</tt> if no account could be found.
+ * @throws org.apache.ki.authc.AuthenticationException
+ * if there is an error obtaining or constructing an AuthenticationInfo object based on the
+ * specified <tt>token</tt> or implementation-specifc login behavior fails.
+ */
+ AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
+
+}
\ No newline at end of file
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/Realm.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/Realm.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Id Author
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/Realm.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/RealmFactory.java
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/realm/RealmFactory.java?rev=752380&view=auto
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/apache/ki/realm/RealmFactory.java (added)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/realm/RealmFactory.java Wed Mar 11 05:40:38 2009
@@ -0,0 +1,53 @@
+/*
+ * 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.ki.realm;
+
+import java.util.Collection;
+
+/**
+ * Enables JSecurity end-users to configure and initialize one or more {@link Realm Realm} instances
+ * in any manner desired.
+ * <p/>
+ * This interface exists to support environments where end-users may not wish to use JSecurity's default
+ * text-based configuration to create and configure realms, and instead wish to retrieve a realm configured in a
+ * proprietary manner. An implementation of this interface can access that proprietary mechanism to retrieve the
+ * already-created <tt>Realm</tt>s.
+ *
+ * <p>The <code>Realm</code> instances returned will used to construct the application's
+ * {@link org.apache.ki.mgt.SecurityManager SecurityManager} instance.
+ *
+ * @since 0.9
+ */
+public interface RealmFactory {
+
+ /**
+ * Returns a collection of {@link Realm Realm} instances that will be used to construct
+ * the application's SecurityManager instance.
+ *
+ * <p>The order of the collection is important. The {@link org.apache.ki.mgt.SecurityManager SecurityManager}
+ * implementation will consult the Realms during authentication (log-in) and authorization (access control)
+ * operations in the collection's <b>iteration order</b>. That is, the resulting collection's
+ * {@link java.util.Iterator Iterator} determines the order in which Realms are used.
+ *
+ * @return the <code>Collection</code> of Realms that the application's <code>SecurityManager</code> will use
+ * for security data access.
+ */
+ Collection<Realm> getRealms();
+
+}
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/RealmFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/RealmFactory.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Id Author
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/RealmFactory.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/SimpleAccountRealm.java
URL: http://svn.apache.org/viewvc/incubator/jsecurity/trunk/core/src/org/apache/ki/realm/SimpleAccountRealm.java?rev=752380&view=auto
==============================================================================
--- incubator/jsecurity/trunk/core/src/org/apache/ki/realm/SimpleAccountRealm.java (added)
+++ incubator/jsecurity/trunk/core/src/org/apache/ki/realm/SimpleAccountRealm.java Wed Mar 11 05:40:38 2009
@@ -0,0 +1,172 @@
+/*
+ * 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.ki.realm;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ki.authc.Account;
+import org.apache.ki.authc.AuthenticationException;
+import org.apache.ki.authc.AuthenticationInfo;
+import org.apache.ki.authc.AuthenticationToken;
+import org.apache.ki.authc.ExpiredCredentialsException;
+import org.apache.ki.authc.LockedAccountException;
+import org.apache.ki.authc.SimpleAccount;
+import org.apache.ki.authc.UsernamePasswordToken;
+import org.apache.ki.authz.AuthorizationInfo;
+import org.apache.ki.authz.SimpleAuthorizingAccount;
+import org.apache.ki.authz.SimpleRole;
+import org.apache.ki.subject.PrincipalCollection;
+import org.apache.ki.util.CollectionUtils;
+
+
+/**
+ * <p>A simple implementation of the {@link Realm Realm} interface that
+ * uses a set of configured user accounts and roles to support authentication and authorization. Each account entry
+ * specifies the username, password, and roles for a user. Roles can also be mapped
+ * to permissions and associated with users.</p>
+ *
+ * <p>User accounts and roles are stored in two {@link org.apache.ki.cache.Cache cache}s, so it is the Cache manager implementation that
+ * determines if this class stores all data in memory or spools to disk or clusters it, etc based on the
+ * Caches it creates.
+ *
+ * @author Jeremy Haile
+ * @author Les Hazlewood
+ * @since 0.1
+ */
+public class SimpleAccountRealm extends AuthorizingRealm {
+
+ //TODO - complete JavaDoc
+
+ protected Map<String, SimpleRole> roles = null;
+
+ public SimpleAccountRealm() {
+ init();
+ }
+
+ public SimpleAccountRealm(String name) {
+ setName(name);
+ init();
+ }
+
+ public void afterAuthorizationCacheSet() {
+ initRoleCache();
+ afterRoleCacheSet();
+ }
+
+ public void afterRoleCacheSet() {
+ }
+
+ protected void initRoleCache() {
+ if (getAuthorizationCache() == null) {
+ initAuthorizationCache();
+ }
+
+ this.roles = new HashMap<String, SimpleRole>();
+ accountAndRoleCachesCreated();
+ }
+
+ protected SimpleAccount getUser(String username) {
+ return (SimpleAccount) getAuthorizationCache().get(username);
+ }
+
+ public boolean accountExists(String username) {
+ return getUser(username) != null;
+ }
+
+ public void addAccount(String username, String password) {
+ addAccount(username, password, (String[])null);
+ }
+
+ public void addAccount(String username, String password, String... roles) {
+ Set<String> roleNames = CollectionUtils.asSet(roles);
+ SimpleAccount account = new SimpleAuthorizingAccount(username, password, getName(), roleNames, null);
+ add(account);
+ }
+
+ protected void add(SimpleAccount account) {
+ Object key = getAuthorizationCacheKey(account.getPrincipals());
+ getAuthorizationCache().put(key, account);
+ }
+
+ protected SimpleRole getRole(String rolename) {
+ return roles.get(rolename);
+ }
+
+ public boolean roleExists(String name) {
+ return getRole(name) != null;
+ }
+
+ public void addRole(String name) {
+ add(new SimpleRole(name));
+ }
+
+ protected void add(SimpleRole role) {
+ roles.put(role.getName(), role);
+ }
+
+ protected static Set<String> toSet(String delimited, String delimiter) {
+ if (delimited == null || delimited.trim().equals("")) {
+ return null;
+ }
+
+ Set<String> values = new HashSet<String>();
+ String[] rolenamesArray = delimited.split(delimiter);
+ for (String s : rolenamesArray) {
+ String trimmed = s.trim();
+ if (trimmed.length() > 0) {
+ values.add(trimmed);
+ }
+ }
+
+ return values;
+ }
+
+ protected void accountAndRoleCachesCreated() {
+ }
+
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+ UsernamePasswordToken upToken = (UsernamePasswordToken) token;
+ SimpleAccount account = (SimpleAccount) getAuthorizationCache().get(upToken.getUsername());
+
+ if( account != null ) {
+
+ if (account.isLocked()) {
+ throw new LockedAccountException("Account [" + account + "] is locked.");
+ }
+ if (account.isCredentialsExpired()) {
+ String msg = "The credentials for account [" + account + "] are expired";
+ throw new ExpiredCredentialsException(msg);
+ }
+
+ }
+
+ return account;
+ }
+
+ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+ return (Account) getAuthorizationCache().get(getAuthorizationCacheKey(principals));
+ }
+
+ protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
+ return principals.fromRealm(getName()).iterator().next(); //returns the username
+ }
+}
\ No newline at end of file
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/SimpleAccountRealm.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/SimpleAccountRealm.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Id Author
Propchange: incubator/jsecurity/trunk/core/src/org/apache/ki/realm/SimpleAccountRealm.java
------------------------------------------------------------------------------
svn:mime-type = text/plain