Java tutorial
/* 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.wiki.auth; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.security.Principal; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.apache.wiki.WikiEngine; import org.apache.wiki.WikiSession; import org.apache.wiki.api.exceptions.WikiException; import org.apache.wiki.auth.authorize.Role; import org.apache.wiki.auth.authorize.WebAuthorizer; import org.apache.wiki.auth.authorize.WebContainerAuthorizer; import org.apache.wiki.auth.login.AnonymousLoginModule; import org.apache.wiki.auth.login.CookieAssertionLoginModule; import org.apache.wiki.auth.login.CookieAuthenticationLoginModule; import org.apache.wiki.auth.login.UserDatabaseLoginModule; import org.apache.wiki.auth.login.WebContainerCallbackHandler; import org.apache.wiki.auth.login.WebContainerLoginModule; import org.apache.wiki.auth.login.WikiCallbackHandler; import org.apache.wiki.event.WikiEventListener; import org.apache.wiki.event.WikiEventManager; import org.apache.wiki.event.WikiSecurityEvent; import org.apache.wiki.util.TextUtil; import org.apache.wiki.util.TimedCounterList; /** * Manages authentication activities for a WikiEngine: user login, logout, and * credential refreshes. This class uses JAAS to determine how users log in. * <p> * The login procedure is protected in addition by a mechanism which prevents * a hacker to try and force-guess passwords by slowing down attempts to log in * into the same account. Every login attempt is recorded, and stored for a while * (currently ten minutes), and each login attempt during that time incurs a penalty * of 2^login attempts milliseconds - that is, 10 login attempts incur a login penalty of 1.024 seconds. * The delay is currently capped to 20 seconds. * * @since 2.3 */ public class AuthenticationManager { /** How many milliseconds the logins are stored before they're cleaned away. */ private static final long LASTLOGINS_CLEANUP_TIME = 10 * 60 * 1000L; // Ten minutes private static final long MAX_LOGIN_DELAY = 20 * 1000L; // 20 seconds /** The name of the built-in cookie assertion module */ public static final String COOKIE_MODULE = CookieAssertionLoginModule.class.getName(); /** The name of the built-in cookie authentication module */ public static final String COOKIE_AUTHENTICATION_MODULE = CookieAuthenticationLoginModule.class.getName(); /** If this jspwiki.properties property is <code>true</code>, logs the IP address of the editor on saving. */ public static final String PROP_STOREIPADDRESS = "jspwiki.storeIPAddress"; /** If this jspwiki.properties property is <code>true</code>, allow cookies to be used for authentication. */ public static final String PROP_ALLOW_COOKIE_AUTH = "jspwiki.cookieAuthentication"; /** * This property determines whether we use JSPWiki authentication or not. * Possible values are AUTH_JAAS or AUTH_CONTAINER. * <p> * Setting this is now deprecated - we do not guarantee that it works. * * @deprecated - to be removed on 2.11.0 */ @Deprecated public static final String PROP_SECURITY = "jspwiki.security"; /** Value specifying that the user wants to use the container-managed security, just like in JSPWiki 2.2. * @deprecated - to be removed on 2.11.0 */ @Deprecated public static final String SECURITY_OFF = "off"; /** Value specifying that the user wants to use the built-in JAAS-based system. * @deprecated - to be removed on 2.11.0 */ @Deprecated public static final String SECURITY_JAAS = "jaas"; /** Whether logins should be throttled to limit brute-forcing attempts. Defaults to true. */ public static final String PROP_LOGIN_THROTTLING = "jspwiki.login.throttling"; protected static final Logger log = Logger.getLogger(AuthenticationManager.class); /** Prefix for LoginModule options key/value pairs. */ protected static final String PREFIX_LOGIN_MODULE_OPTIONS = "jspwiki.loginModule.options."; /** If this jspwiki.properties property is <code>true</code>, allow cookies to be used to assert identities. */ protected static final String PROP_ALLOW_COOKIE_ASSERTIONS = "jspwiki.cookieAssertions"; /** The {@link javax.security.auth.spi.LoginModule} to use for custom authentication. */ protected static final String PROP_LOGIN_MODULE = "jspwiki.loginModule.class"; /** Empty Map passed to JAAS {@link #doJAASLogin(Class, CallbackHandler, Map)} method. */ protected static final Map<String, String> EMPTY_MAP = Collections .unmodifiableMap(new HashMap<String, String>()); /** Class (of type LoginModule) to use for custom authentication. */ protected Class<? extends LoginModule> m_loginModuleClass = UserDatabaseLoginModule.class; /** Options passed to {@link javax.security.auth.spi.LoginModule#initialize(Subject, CallbackHandler, Map, Map)}; * initialized by {@link #initialize(WikiEngine, Properties)}. */ protected Map<String, String> m_loginModuleOptions = new HashMap<String, String>(); /** Just to provide compatibility with the old versions. The same * as SECURITY_OFF. * * @deprecated use {@link #SECURITY_OFF} instead - to be removed on 2.11.0 */ @Deprecated protected static final String SECURITY_CONTAINER = "container"; /** The default {@link javax.security.auth.spi.LoginModule} class name to use for custom authentication. */ private static final String DEFAULT_LOGIN_MODULE = "org.apache.wiki.auth.login.UserDatabaseLoginModule"; /** Empty principal set. */ private static final Set<Principal> NO_PRINCIPALS = new HashSet<Principal>(); /** Static Boolean for lazily-initializing the "allows assertions" flag */ private boolean m_allowsCookieAssertions = true; private boolean m_throttleLogins = true; /** Static Boolean for lazily-initializing the "allows cookie authentication" flag */ private boolean m_allowsCookieAuthentication = false; private WikiEngine m_engine = null; /** If true, logs the IP address of the editor */ private boolean m_storeIPAddress = true; /** Keeps a list of the usernames who have attempted a login recently. */ private TimedCounterList<String> m_lastLoginAttempts = new TimedCounterList<String>(); /** * Creates an AuthenticationManager instance for the given WikiEngine and * the specified set of properties. All initialization for the modules is * done here. * @param engine the wiki engine * @param props the properties used to initialize the wiki engine * @throws WikiException if the AuthenticationManager cannot be initialized */ @SuppressWarnings("unchecked") public void initialize(WikiEngine engine, Properties props) throws WikiException { m_engine = engine; m_storeIPAddress = TextUtil.getBooleanProperty(props, PROP_STOREIPADDRESS, m_storeIPAddress); // Should we allow cookies for assertions? (default: yes) m_allowsCookieAssertions = TextUtil.getBooleanProperty(props, PROP_ALLOW_COOKIE_ASSERTIONS, true); // Should we allow cookies for authentication? (default: no) m_allowsCookieAuthentication = TextUtil.getBooleanProperty(props, PROP_ALLOW_COOKIE_AUTH, false); // Should we throttle logins? (default: yes) m_throttleLogins = TextUtil.getBooleanProperty(props, PROP_LOGIN_THROTTLING, true); // Look up the LoginModule class String loginModuleClassName = TextUtil.getStringProperty(props, PROP_LOGIN_MODULE, DEFAULT_LOGIN_MODULE); try { m_loginModuleClass = (Class<? extends LoginModule>) Class.forName(loginModuleClassName); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new WikiException("Could not instantiate LoginModule class.", e); } // Initialize the LoginModule options initLoginModuleOptions(props); } /** * Returns true if this WikiEngine uses container-managed authentication. * This method is used primarily for cosmetic purposes in the JSP tier, and * performs no meaningful security function per se. Delegates to * {@link org.apache.wiki.auth.authorize.WebContainerAuthorizer#isContainerAuthorized()}, * if used as the external authorizer; otherwise, returns <code>false</code>. * @return <code>true</code> if the wiki's authentication is managed by * the container, <code>false</code> otherwise */ public boolean isContainerAuthenticated() { try { Authorizer authorizer = m_engine.getAuthorizationManager().getAuthorizer(); if (authorizer instanceof WebContainerAuthorizer) { return ((WebContainerAuthorizer) authorizer).isContainerAuthorized(); } } catch (WikiException e) { // It's probably ok to fail silently... } return false; } /** * <p>Logs in the user by attempting to populate a WikiSession Subject from * a web servlet request by examining the request * for the presence of container credentials and user cookies. The processing * logic is as follows: * </p> * <ul> * <li>If the WikiSession had previously been unauthenticated, check to see if * user has subsequently authenticated. To be considered "authenticated," * the request must supply one of the following (in order of preference): * the container <code>userPrincipal</code>, container <code>remoteUser</code>, * or authentication cookie. If the user is authenticated, this method fires event * {@link org.apache.wiki.event.WikiSecurityEvent#LOGIN_AUTHENTICATED} * with two parameters: a Principal representing the login principal, * and the current WikiSession. In addition, if the authorizer is of type * WebContainerAuthorizer, this method iterates through the container roles returned by * {@link org.apache.wiki.auth.authorize.WebContainerAuthorizer#getRoles()}, * tests for membership in each one, and adds those that pass to the Subject's principal set.</li> * <li>If, after checking for authentication, the WikiSession is still Anonymous, * this method next checks to see if the user has "asserted" an identity * by supplying an assertion cookie. If the user is found to be asserted, * this method fires event {@link org.apache.wiki.event.WikiSecurityEvent#LOGIN_ASSERTED} * with two parameters: <code>WikiPrincipal(<em>cookievalue</em>)</code>, and * the current WikiSession.</li> * <li>If, after checking for authenticated and asserted status, the WikiSession is * <em>still</em> anonymous, this method fires event * {@link org.apache.wiki.event.WikiSecurityEvent#LOGIN_ANONYMOUS} with * two parameters: <code>WikiPrincipal(<em>remoteAddress</em>)</code>, * and the current WikiSession </li> * </ul> * @param request servlet request for this user * @return always returns <code>true</code> (because anonymous login, at least, will always succeed) * @throws org.apache.wiki.auth.WikiSecurityException if the user cannot be logged in for any reason * @since 2.3 */ public boolean login(HttpServletRequest request) throws WikiSecurityException { HttpSession httpSession = request.getSession(); WikiSession session = SessionMonitor.getInstance(m_engine).find(httpSession); AuthenticationManager authenticationMgr = m_engine.getAuthenticationManager(); AuthorizationManager authorizationMgr = m_engine.getAuthorizationManager(); CallbackHandler handler = null; Map<String, String> options = EMPTY_MAP; // If user not authenticated, check if container logged them in, or if // there's an authentication cookie if (!session.isAuthenticated()) { // Create a callback handler handler = new WebContainerCallbackHandler(m_engine, request); // Execute the container login module, then (if that fails) the cookie auth module Set<Principal> principals = authenticationMgr.doJAASLogin(WebContainerLoginModule.class, handler, options); if (principals.size() == 0 && authenticationMgr.allowsCookieAuthentication()) { principals = authenticationMgr.doJAASLogin(CookieAuthenticationLoginModule.class, handler, options); } // If the container logged the user in successfully, tell the WikiSession (and add all of the Principals) if (principals.size() > 0) { fireEvent(WikiSecurityEvent.LOGIN_AUTHENTICATED, getLoginPrincipal(principals), session); for (Principal principal : principals) { fireEvent(WikiSecurityEvent.PRINCIPAL_ADD, principal, session); } // Add all appropriate Authorizer roles injectAuthorizerRoles(session, authorizationMgr.getAuthorizer(), request); } } // If user still not authenticated, check if assertion cookie was supplied if (!session.isAuthenticated() && authenticationMgr.allowsCookieAssertions()) { // Execute the cookie assertion login module Set<Principal> principals = authenticationMgr.doJAASLogin(CookieAssertionLoginModule.class, handler, options); if (principals.size() > 0) { fireEvent(WikiSecurityEvent.LOGIN_ASSERTED, getLoginPrincipal(principals), session); } } // If user still anonymous, use the remote address if (session.isAnonymous()) { Set<Principal> principals = authenticationMgr.doJAASLogin(AnonymousLoginModule.class, handler, options); if (principals.size() > 0) { fireEvent(WikiSecurityEvent.LOGIN_ANONYMOUS, getLoginPrincipal(principals), session); return true; } } // If by some unusual turn of events the Anonymous login module doesn't work, login failed! return false; } /** * Attempts to perform a WikiSession login for the given username/password * combination using JSPWiki's custom authentication mode. This method is identical to * {@link #login(WikiSession, String, String)}, except that user's HTTP request is not made available * to LoginModules via the {@link org.apache.wiki.auth.login.HttpRequestCallback}. * @param session the current wiki session; may not be <code>null</code>. * @param username The user name. This is a login name, not a WikiName. In * most cases they are the same, but in some cases, they might * not be. * @param password the password * @return true, if the username/password is valid * @throws org.apache.wiki.auth.WikiSecurityException if the Authorizer or UserManager cannot be obtained * @deprecated use {@link #login(WikiSession, HttpServletRequest, String, String)} instead */ public boolean login(WikiSession session, String username, String password) throws WikiSecurityException { return login(session, null, username, password); } /** * Attempts to perform a WikiSession login for the given username/password * combination using JSPWiki's custom authentication mode. In order to log in, * the JAAS LoginModule supplied by the WikiEngine property {@link #PROP_LOGIN_MODULE} * will be instantiated, and its * {@link javax.security.auth.spi.LoginModule#initialize(Subject, CallbackHandler, Map, Map)} * method will be invoked. By default, the {@link org.apache.wiki.auth.login.UserDatabaseLoginModule} * class will be used. When the LoginModule's <code>initialize</code> method is invoked, * an options Map populated by properties keys prefixed by {@link #PREFIX_LOGIN_MODULE_OPTIONS} * will be passed as a parameter. * @param session the current wiki session; may not be <code>null</code>. * @param request the user's HTTP request. This parameter may be <code>null</code>, but the configured * LoginModule will not have access to the HTTP request in this case. * @param username The user name. This is a login name, not a WikiName. In * most cases they are the same, but in some cases, they might * not be. * @param password the password * @return true, if the username/password is valid * @throws org.apache.wiki.auth.WikiSecurityException if the Authorizer or UserManager cannot be obtained */ public boolean login(WikiSession session, HttpServletRequest request, String username, String password) throws WikiSecurityException { if (session == null) { log.error("No wiki session provided, cannot log in."); return false; } // Protect against brute-force password guessing if configured to do so if (m_throttleLogins) { delayLogin(username); } CallbackHandler handler = new WikiCallbackHandler(m_engine, null, username, password); // Execute the user's specified login module Set<Principal> principals = doJAASLogin(m_loginModuleClass, handler, m_loginModuleOptions); if (principals.size() > 0) { fireEvent(WikiSecurityEvent.LOGIN_AUTHENTICATED, getLoginPrincipal(principals), session); for (Principal principal : principals) { fireEvent(WikiSecurityEvent.PRINCIPAL_ADD, principal, session); } // Add all appropriate Authorizer roles injectAuthorizerRoles(session, m_engine.getAuthorizationManager().getAuthorizer(), null); return true; } return false; } /** * This method builds a database of login names that are being attempted, and will try to * delay if there are too many requests coming in for the same username. * <p> * The current algorithm uses 2^loginattempts as the delay in milliseconds, i.e. * at 10 login attempts it'll add 1.024 seconds to the login. * * @param username The username that is being logged in */ private void delayLogin(String username) { try { m_lastLoginAttempts.cleanup(LASTLOGINS_CLEANUP_TIME); int count = m_lastLoginAttempts.count(username); long delay = Math.min(1 << count, MAX_LOGIN_DELAY); log.debug("Sleeping for " + delay + " ms to allow login."); Thread.sleep(delay); m_lastLoginAttempts.add(username); } catch (InterruptedException e) { // FALLTHROUGH is fine } } /** * Logs the user out by retrieving the WikiSession associated with the * HttpServletRequest and unbinding all of the Subject's Principals, * except for {@link Role#ALL}, {@link Role#ANONYMOUS}. * is a cheap-and-cheerful way to do it without invoking JAAS LoginModules. * The logout operation will also flush the JSESSIONID cookie from * the user's browser session, if it was set. * @param request the current HTTP request */ public void logout(HttpServletRequest request) { if (request == null) { log.error("No HTTP reqest provided; cannot log out."); return; } HttpSession session = request.getSession(); String sid = (session == null) ? "(null)" : session.getId(); if (log.isDebugEnabled()) { log.debug("Invalidating WikiSession for session ID=" + sid); } // Retrieve the associated WikiSession and clear the Principal set WikiSession wikiSession = WikiSession.getWikiSession(m_engine, request); Principal originalPrincipal = wikiSession.getLoginPrincipal(); wikiSession.invalidate(); // Remove the wikiSession from the WikiSession cache WikiSession.removeWikiSession(m_engine, request); // We need to flush the HTTP session too if (session != null) { session.invalidate(); } // Log the event fireEvent(WikiSecurityEvent.LOGOUT, originalPrincipal, null); } /** * Determines whether this WikiEngine allows users to assert identities using * cookies instead of passwords. This is determined by inspecting * the WikiEngine property {@link #PROP_ALLOW_COOKIE_ASSERTIONS}. * @return <code>true</code> if cookies are allowed */ public boolean allowsCookieAssertions() { return m_allowsCookieAssertions; } /** * Determines whether this WikiEngine allows users to authenticate using * cookies instead of passwords. This is determined by inspecting * the WikiEngine property {@link #PROP_ALLOW_COOKIE_AUTH}. * @return <code>true</code> if cookies are allowed for authentication * @since 2.5.62 */ public boolean allowsCookieAuthentication() { return m_allowsCookieAuthentication; } /** * Determines whether the supplied Principal is a "role principal". * @param principal the principal to test * @return <code>true</code> if the Principal is of type * {@link GroupPrincipal} or * {@link org.apache.wiki.auth.authorize.Role}, * <code>false</code> otherwise */ public static boolean isRolePrincipal(Principal principal) { return principal instanceof Role || principal instanceof GroupPrincipal; } /** * Determines whether the supplied Principal is a "user principal". * @param principal the principal to test * @return <code>false</code> if the Principal is of type * {@link GroupPrincipal} or * {@link org.apache.wiki.auth.authorize.Role}, * <code>true</code> otherwise */ public static boolean isUserPrincipal(Principal principal) { return !isRolePrincipal(principal); } /** * Instantiates and executes a single JAAS * {@link javax.security.auth.spi.LoginModule}, and returns a Set of * Principals that results from a successful login. The LoginModule is instantiated, * then its {@link javax.security.auth.spi.LoginModule#initialize(Subject, CallbackHandler, Map, Map)} * method is called. The parameters passed to <code>initialize</code> is a * dummy Subject, an empty shared-state Map, and an options Map the caller supplies. * * @param clazz * the LoginModule class to instantiate * @param handler * the callback handler to supply to the LoginModule * @param options * a Map of key/value strings for initializing the LoginModule * @return the set of Principals returned by the JAAS method {@link Subject#getPrincipals()} * @throws WikiSecurityException * if the LoginModule could not be instantiated for any reason */ protected Set<Principal> doJAASLogin(Class<? extends LoginModule> clazz, CallbackHandler handler, Map<String, String> options) throws WikiSecurityException { // Instantiate the login module LoginModule loginModule = null; try { loginModule = clazz.newInstance(); } catch (InstantiationException e) { throw new WikiSecurityException(e.getMessage(), e); } catch (IllegalAccessException e) { throw new WikiSecurityException(e.getMessage(), e); } // Initialize the LoginModule Subject subject = new Subject(); loginModule.initialize(subject, handler, EMPTY_MAP, options); // Try to log in: boolean loginSucceeded = false; boolean commitSucceeded = false; try { loginSucceeded = loginModule.login(); if (loginSucceeded) { commitSucceeded = loginModule.commit(); } } catch (LoginException e) { // Login or commit failed! No principal for you! } // If we successfully logged in & committed, return all the principals if (loginSucceeded && commitSucceeded) { return subject.getPrincipals(); } return NO_PRINCIPALS; } /** * Looks up and obtains a configuration file inside the WEB-INF folder of a * wiki webapp. * @param engine the wiki engine * @param name the file to obtain, <em>e.g.</em>, <code>jspwiki.policy</code> * @return the URL to the file */ protected static URL findConfigFile(WikiEngine engine, String name) { log.info("looking for " + name + " inside WEB-INF "); // Try creating an absolute path first File defaultFile = null; if (engine.getRootPath() != null) { defaultFile = new File(engine.getRootPath() + "/WEB-INF/" + name); } if (defaultFile != null && defaultFile.exists()) { try { return defaultFile.toURI().toURL(); } catch (MalformedURLException e) { // Shouldn't happen, but log it if it does log.warn("Malformed URL: " + e.getMessage()); } } // Ok, the absolute path didn't work; try other methods URL path = null; if (engine.getServletContext() != null) { OutputStream os = null; InputStream is = null; try { log.info("looking for /" + name + " on classpath"); // create a tmp file of the policy loaded as an InputStream and return the URL to it // is = AuthenticationManager.class.getResourceAsStream("/" + name); if (is == null) { throw new FileNotFoundException(name + " not found"); } File tmpFile = File.createTempFile("temp." + name, ""); tmpFile.deleteOnExit(); os = new FileOutputStream(tmpFile); byte[] buff = new byte[1024]; int bytes = 0; while ((bytes = is.read(buff)) != -1) { os.write(buff, 0, bytes); } path = tmpFile.toURI().toURL(); } catch (MalformedURLException e) { // This should never happen unless I screw up log.fatal("Your code is b0rked. You are a bad person.", e); } catch (IOException e) { log.error("failed to load security policy from file " + name + ",stacktrace follows", e); } finally { IOUtils.closeQuietly(is); IOUtils.closeQuietly(os); } } return path; } /** * Returns the first Principal in a set that isn't a {@link org.apache.wiki.auth.authorize.Role} or * {@link org.apache.wiki.auth.GroupPrincipal}. * @param principals the principal set * @return the login principal */ protected Principal getLoginPrincipal(Set<Principal> principals) { for (Principal principal : principals) { if (isUserPrincipal(principal)) { return principal; } } return null; } // events processing ....................................................... /** * Registers a WikiEventListener with this instance. * This is a convenience method. * @param listener the event listener */ public synchronized void addWikiEventListener(WikiEventListener listener) { WikiEventManager.addWikiEventListener(this, listener); } /** * Un-registers a WikiEventListener with this instance. * This is a convenience method. * @param listener the event listener */ public synchronized void removeWikiEventListener(WikiEventListener listener) { WikiEventManager.removeWikiEventListener(this, listener); } /** * Fires a WikiSecurityEvent of the provided type, Principal and target Object * to all registered listeners. * * @see org.apache.wiki.event.WikiSecurityEvent * @param type the event type to be fired * @param principal the subject of the event, which may be <code>null</code> * @param target the changed Object, which may be <code>null</code> */ protected void fireEvent(int type, Principal principal, Object target) { if (WikiEventManager.isListening(this)) { WikiEventManager.fireEvent(this, new WikiSecurityEvent(this, type, principal, target)); } } /** * Initializes the options Map supplied to the configured LoginModule every time it is invoked. * The properties and values extracted from * <code>jspwiki.properties</code> are of the form * <code>jspwiki.loginModule.options.<var>param</var> = <var>value</var>, where * <var>param</var> is the key name, and <var>value</var> is the value. * @param props the properties used to initialize JSPWiki * @throws IllegalArgumentException if any of the keys are duplicated */ private void initLoginModuleOptions(Properties props) { for (Object key : props.keySet()) { String propName = key.toString(); if (propName.startsWith(PREFIX_LOGIN_MODULE_OPTIONS)) { // Extract the option name and value String optionKey = propName.substring(PREFIX_LOGIN_MODULE_OPTIONS.length()).trim(); if (optionKey.length() > 0) { String optionValue = props.getProperty(propName); // Make sure the key is unique before stashing the key/value pair if (m_loginModuleOptions.containsKey(optionKey)) { throw new IllegalArgumentException( "JAAS LoginModule key " + propName + " cannot be specified twice!"); } m_loginModuleOptions.put(optionKey, optionValue); } } } } /** * After successful login, this method is called to inject authorized role Principals into the WikiSession. * To determine which roles should be injected, the configured Authorizer * is queried for the roles it knows about by calling {@link org.apache.wiki.auth.Authorizer#getRoles()}. * Then, each role returned by the authorizer is tested by calling {@link org.apache.wiki.auth.Authorizer#isUserInRole(WikiSession, Principal)}. * If this check fails, and the Authorizer is of type WebAuthorizer, the role is checked again by calling * {@link org.apache.wiki.auth.authorize.WebAuthorizer#isUserInRole(javax.servlet.http.HttpServletRequest, Principal)}). * Any roles that pass the test are injected into the Subject by firing appropriate authentication events. * @param session the user's current WikiSession * @param authorizer the WikiEngine's configured Authorizer * @param request the user's HTTP session, which may be <code>null</code> */ private void injectAuthorizerRoles(WikiSession session, Authorizer authorizer, HttpServletRequest request) { // Test each role the authorizer knows about for (Principal role : authorizer.getRoles()) { // Test the Authorizer if (authorizer.isUserInRole(session, role)) { fireEvent(WikiSecurityEvent.PRINCIPAL_ADD, role, session); if (log.isDebugEnabled()) { log.debug("Added authorizer role " + role.getName() + "."); } } // If web authorizer, test the request.isInRole() method also else if (request != null && authorizer instanceof WebAuthorizer) { WebAuthorizer wa = (WebAuthorizer) authorizer; if (wa.isUserInRole(request, role)) { fireEvent(WikiSecurityEvent.PRINCIPAL_ADD, role, session); if (log.isDebugEnabled()) { log.debug("Added container role " + role.getName() + "."); } } } } } }