📄 authenticationmanager.java
字号:
/* JSPWiki - a JSP-based WikiWiki clone. 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 com.ecyrd.jspwiki.auth;import java.io.File;import java.net.MalformedURLException;import java.net.URL;import java.security.Principal;import java.util.*;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.log4j.Logger;import com.ecyrd.jspwiki.TextUtil;import com.ecyrd.jspwiki.WikiEngine;import com.ecyrd.jspwiki.WikiException;import com.ecyrd.jspwiki.WikiSession;import com.ecyrd.jspwiki.auth.authorize.Role;import com.ecyrd.jspwiki.auth.authorize.WebAuthorizer;import com.ecyrd.jspwiki.auth.authorize.WebContainerAuthorizer;import com.ecyrd.jspwiki.auth.login.*;import com.ecyrd.jspwiki.event.WikiEventListener;import com.ecyrd.jspwiki.event.WikiEventManager;import com.ecyrd.jspwiki.event.WikiSecurityEvent;import com.ecyrd.jspwiki.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. * * @author Andrew Jaquith * @author Erik Bunn * @since 2.3 */public final 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 */ 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. */ public static final String SECURITY_OFF = "off"; /** Value specifying that the user wants to use the built-in JAAS-based system */ 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 */ 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 = "com.ecyrd.jspwiki.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; private boolean m_useJAAS = 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 final void initialize( WikiEngine engine, Properties props ) throws WikiException { m_engine = engine; m_storeIPAddress = TextUtil.getBooleanProperty( props, PROP_STOREIPADDRESS, m_storeIPAddress ); // Should J2SE policies be used for authorization? m_useJAAS = SECURITY_JAAS.equals(props.getProperty( PROP_SECURITY, SECURITY_JAAS )); // 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(e.getMessage()); } // 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 com.ecyrd.jspwiki.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 final boolean isContainerAuthenticated() { if( !m_useJAAS ) return true; 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 com.ecyrd.jspwiki.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 com.ecyrd.jspwiki.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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -