--- ./src/com/ecyrd/jspwiki/auth/AuthenticationManager.java.orig 2009-03-04 12:34:30.000000000 +1100 +++ ./src/com/ecyrd/jspwiki/auth/AuthenticationManager.java 2009-03-04 14:06:33.000000000 +1100 @@ -109,20 +109,28 @@ 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"; + /** pProperty specifying if the Login Modules can change login names or passwords. */ + protected static final String PROP_CHANGE_LOGIN = "jspwiki.loginModule.canChangeLoginName"; + protected static final String PROP_CHANGE_PASSWORD = "jspwiki.loginModule.canChangePassword"; /** Empty Map passed to JAAS {@link #doJAASLogin(Class, CallbackHandler, Map)} method. */ protected static final Map EMPTY_MAP = Collections.unmodifiableMap( new HashMap() ); /** Class (of type LoginModule) to use for custom authentication. */ protected Class 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 m_loginModuleOptions = new HashMap(); + /** Can this LoginModule change the username or password? + * initialized by {@link #initialize(WikiEngine, Properties)}. */ + protected boolean m_canChangeLoginName = true; + protected boolean m_canChangePassword = true; + /** Just to provide compatibility with the old versions. The same * as SECURITY_OFF. * * @deprecated use {@link #SECURITY_OFF} instead */ @@ -152,10 +160,42 @@ /** Keeps a list of the usernames who have attempted a login recently. */ private TimedCounterList m_lastLoginAttempts = new TimedCounterList(); /** + * Returns true if the current Authentication manager is capable of + * changing the login name. Defaults to true for most LoginModules + * except when using container based authentication. + * + * @return true if it is possible to change the password, + * false otherwise. + */ + public final boolean canChangeLoginName() + { + if (isContainerAuthenticated()) + return false; + else + return m_canChangeLoginName; + } + + /** + * Returns true if the current Authentication manager is capable of + * changing the password. Defaults to true for most LoginModules + * except when using container based authentication. + * + * @return true if it is possible to change the password, + * false otherwise. + */ + public final boolean canChangePassword() + { + if (isContainerAuthenticated()) + return false; + else + return m_canChangePassword; + } + + /** * 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 @@ -195,10 +235,17 @@ { e.printStackTrace(); throw new WikiException(e.getMessage()); } + // Can this LoginModule change names or passwords? + m_canChangeLoginName = TextUtil.getBooleanProperty( props, + PROP_CHANGE_LOGIN, + true ); + m_canChangePassword = TextUtil.getBooleanProperty( props, + PROP_CHANGE_PASSWORD, + true ); // Initialize the LoginModule options initLoginModuleOptions( props ); } /** --- ./src/com/ecyrd/jspwiki/auth/UserManager.java.orig 2009-03-04 14:15:05.000000000 +1100 +++ ./src/com/ecyrd/jspwiki/auth/UserManager.java 2009-03-04 14:22:51.000000000 +1100 @@ -361,10 +361,11 @@ // If the profile doesn't need approval, then just log the user in try { AuthenticationManager mgr = m_engine.getAuthenticationManager(); + // TODO: Why is isContainerAuthenticated() checked here? if ( newProfile && !mgr.isContainerAuthenticated() ) { mgr.login( session, profile.getLoginName(), profile.getPassword() ); } } @@ -440,12 +441,12 @@ loginName = InputValidator.isBlank( loginName ) ? null : loginName; password = InputValidator.isBlank( password ) ? null : password; fullname = InputValidator.isBlank( fullname ) ? null : fullname; email = InputValidator.isBlank( email ) ? null : email; - // A special case if we have container authentication - if ( m_engine.getAuthenticationManager().isContainerAuthenticated() ) + // A special case if we can't rename accounts + if ( !m_engine.getAuthenticationManager().canChangeLoginName() ) { // If authenticated, login name is always taken from container if ( context.getWikiSession().isAuthenticated() ) { loginName = context.getWikiSession().getLoginPrincipal().getName(); @@ -496,23 +497,24 @@ } break; } } - // If container-managed auth and user not logged in, throw an error - if ( m_engine.getAuthenticationManager().isContainerAuthenticated() + // If we can't change or create loginnames and user not logged in, + // throw an error + if ( !m_engine.getAuthenticationManager().canChangeLoginName() && !context.getWikiSession().isAuthenticated() ) { session.addMessage( SESSION_MESSAGES, rb.getString("security.error.createprofilebeforelogin") ); } validator.validateNotNull( profile.getLoginName(), rb.getString("security.user.loginname") ); validator.validateNotNull( profile.getFullname(), rb.getString("security.user.fullname") ); validator.validate( profile.getEmail(), rb.getString("security.user.email"), InputValidator.EMAIL ); // If new profile, passwords must match and can't be null - if ( !m_engine.getAuthenticationManager().isContainerAuthenticated() ) + if ( m_engine.getAuthenticationManager().canChangePassword() ) { String password = profile.getPassword(); if ( password == null ) { if ( isNew ) --- ./src/com/ecyrd/jspwiki/tags/UserProfileTag.java.orig 2009-03-04 12:46:03.000000000 +1100 +++ ./src/com/ecyrd/jspwiki/tags/UserProfileTag.java 2009-03-04 13:28:48.000000000 +1100 @@ -180,22 +180,34 @@ { result = user.getName(); } } } - else if ( CHANGE_PASSWORD.equals( m_prop ) || CHANGE_LOGIN_NAME.equals( m_prop ) ) + else if ( CHANGE_LOGIN_NAME.equals( m_prop ) || NOT_CHANGE_LOGIN_NAME.equals( m_prop ) ) { - AuthenticationManager authMgr = m_wikiContext.getEngine().getAuthenticationManager(); - if ( !authMgr.isContainerAuthenticated() ) + boolean canChange = m_wikiContext.getEngine().getAuthenticationManager().canChangeLoginName(); + + // Cheap and nasty trick to check for boolean NOT + if ( m_prop.charAt(0) == '!' ) + { + canChange = !canChange; + } + if ( canChange ) { return EVAL_BODY_INCLUDE; } } - else if ( NOT_CHANGE_PASSWORD.equals( m_prop ) || NOT_CHANGE_LOGIN_NAME.equals( m_prop ) ) + else if ( CHANGE_PASSWORD.equals( m_prop ) || NOT_CHANGE_PASSWORD.equals( m_prop ) ) { - AuthenticationManager authMgr = m_wikiContext.getEngine().getAuthenticationManager(); - if ( authMgr.isContainerAuthenticated() ) + boolean canChange = m_wikiContext.getEngine().getAuthenticationManager().canChangePassword(); + + // Cheap and nasty trick to check for boolean NOT + if ( m_prop.charAt(0) == '!' ) + { + canChange = !canChange; + } + if ( canChange ) { return EVAL_BODY_INCLUDE; } } --- ./etc/jspwiki.properties.tmpl.orig 2009-03-04 14:31:19.000000000 +1100 +++ ./etc/jspwiki.properties.tmpl 2009-03-04 14:34:11.000000000 +1100 @@ -434,10 +434,17 @@ # The implementation MUST have a zero-argument constructor (as noted in the # javax.security.auth.spi.LoginModule Javadocs). jspwiki.loginModule.class = com.ecyrd.jspwiki.auth.login.UserDatabaseLoginModule # +# Not all LoginModules allow you to change login names or passwords. Set these +# options to false if you use a custom LoginModule which doesn't allow these +# changes. +#jspwiki.loginModule.canChangeLoginName = true +#jspwiki.loginModule.canChangePassword = true + +# # JAAS LoginContext parameters used to initialize the LoginModule. Note that 'param1' # etc. should be replaced with the actual parameter names. The parameter names and # values will be loaded to a Map and passed to the LoginModule as the 'options' parameter # when its initialize() method is called. The default UserDatabaseLoginModule class does # not need any options. --- ./etc/jspwiki.properties.orig 2009-03-04 14:34:37.000000000 +1100 +++ ./etc/jspwiki.properties 2009-03-04 14:35:18.000000000 +1100 @@ -434,10 +434,17 @@ # The implementation MUST have a zero-argument constructor (as noted in the # javax.security.auth.spi.LoginModule Javadocs). jspwiki.loginModule.class = com.ecyrd.jspwiki.auth.login.UserDatabaseLoginModule # +# Not all LoginModules allow you to change login names or passwords. Set these +# options to false if you use a custom LoginModule which doesn't allow these +# changes. +#jspwiki.loginModule.canChangeLoginName = true +#jspwiki.loginModule.canChangePassword = true + +# # JAAS LoginContext parameters used to initialize the LoginModule. Note that 'param1' # etc. should be replaced with the actual parameter names. The parameter names and # values will be loaded to a Map and passed to the LoginModule as the 'options' parameter # when its initialize() method is called. The default UserDatabaseLoginModule class does # not need any options.