From b6a49570cf11e306b8badab3e69dd43eff78171c Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 17 Feb 2017 23:06:05 +0100 Subject: [PATCH] refactor AuthenticationInfoCollector --- .../sonia/scm/security/AdminDetector.java | 105 ++++++ .../security/AuthenticationInfoCollector.java | 314 ++++-------------- .../sonia/scm/security/GroupCollector.java | 72 +++- .../security/LocalDatabaseSynchronizer.java | 127 +++++++ .../java/sonia/scm/security/SessionStore.java | 66 ++++ .../java/sonia/scm/security/ScmRealmTest.java | 16 +- 6 files changed, 436 insertions(+), 264 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/security/AdminDetector.java create mode 100644 scm-webapp/src/main/java/sonia/scm/security/LocalDatabaseSynchronizer.java create mode 100644 scm-webapp/src/main/java/sonia/scm/security/SessionStore.java diff --git a/scm-webapp/src/main/java/sonia/scm/security/AdminDetector.java b/scm-webapp/src/main/java/sonia/scm/security/AdminDetector.java new file mode 100644 index 0000000000..ddc43d8b0a --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/security/AdminDetector.java @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2014, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ +package sonia.scm.security; + +import com.google.inject.Inject; +import java.util.Collection; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.config.ScmConfiguration; +import sonia.scm.user.User; +import sonia.scm.util.Util; + +/** + * Detects administrator from configuration. + * + * @author Sebastian Sdorra + * @since 1.52 + */ +public class AdminDetector { + + /** + * the logger for AdminDetector + */ + private static final Logger LOG = LoggerFactory.getLogger(AdminDetector.class); + + private final ScmConfiguration configuration; + + /** + * Constructs admin detector. + * + * @param configuration scm-manager main configuration + */ + @Inject + public AdminDetector(ScmConfiguration configuration) { + this.configuration = configuration; + } + + /** + * Checks is the authenticated user is marked as administrator by {@link ScmConfiguration}. + * + * @param user authenticated user + * @param groups groups of authenticated user + */ + public void checkForAuthenticatedAdmin(User user, Set groups) { + if (!user.isAdmin()) { + user.setAdmin(isAdminByConfiguration(user, groups)); + + if (LOG.isDebugEnabled() && user.isAdmin()) { + LOG.debug("user {} is marked as admin by configuration", user.getName()); + } + } + else if (LOG.isDebugEnabled()) { + LOG.debug("authenticator {} marked user {} as admin", user.getType(), user.getName()); + } + } + + private boolean isAdminByConfiguration(User user, Collection groups) { + boolean result = false; + Set adminUsers = configuration.getAdminUsers(); + + if (adminUsers != null) { + result = adminUsers.contains(user.getName()); + } + + if (!result) { + Set adminGroups = configuration.getAdminGroups(); + + if (adminGroups != null) { + result = Util.containsOne(adminGroups, groups); + } + } + + return result; + } + +} diff --git a/scm-webapp/src/main/java/sonia/scm/security/AuthenticationInfoCollector.java b/scm-webapp/src/main/java/sonia/scm/security/AuthenticationInfoCollector.java index 7548c870f1..8eb4de4c48 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/AuthenticationInfoCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/AuthenticationInfoCollector.java @@ -30,295 +30,95 @@ */ package sonia.scm.security; -import com.google.common.base.Joiner; -import com.google.common.collect.Sets; import com.google.inject.Inject; -import com.google.inject.Provider; -import java.io.IOException; -import java.util.Collection; import java.util.Set; -import javax.servlet.http.HttpServletRequest; -import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.DisabledAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.HandlerEvent; -import sonia.scm.config.ScmConfiguration; -import sonia.scm.group.Group; -import sonia.scm.group.GroupManager; import sonia.scm.group.GroupNames; import sonia.scm.user.User; -import sonia.scm.user.UserDAO; -import sonia.scm.user.UserEventHack; -import sonia.scm.user.UserException; -import sonia.scm.user.UserManager; -import sonia.scm.util.Util; import sonia.scm.web.security.AuthenticationResult; /** - * + * Collects authentication info for realm. + * * @author Sebastian Sdorra + * @since 1.52 */ public class AuthenticationInfoCollector { - - private static final String SCM_CREDENTIALS = "SCM_CREDENTIALS"; /** * the logger for AuthenticationInfoCollector */ - private static final Logger logger = LoggerFactory.getLogger(AuthenticationInfoCollector.class); + private static final Logger LOG = LoggerFactory.getLogger(AuthenticationInfoCollector.class); - private final ScmConfiguration configuration; - private final UserManager userManager; - private final GroupManager groupManager; - private final UserDAO userDAO; - private final Provider requestProvider; + private final LocalDatabaseSynchronizer synchronizer; + private final GroupCollector groupCollector; + private final SessionStore sessionStore; + /** + * Construct a new AuthenticationInfoCollector. + * + * @param synchronizer local database synchronizer + * @param groupCollector groups collector + * @param sessionStore session store + */ @Inject - public AuthenticationInfoCollector(ScmConfiguration configuration, UserManager userManager, GroupManager groupManager, - UserDAO userDAO, Provider requestProvider) { - this.configuration = configuration; - this.userManager = userManager; - this.groupManager = groupManager; - this.userDAO = userDAO; - this.requestProvider = requestProvider; + public AuthenticationInfoCollector( + LocalDatabaseSynchronizer synchronizer, GroupCollector groupCollector, SessionStore sessionStore + ) { + this.synchronizer = synchronizer; + this.groupCollector = groupCollector; + this.sessionStore = sessionStore; } - AuthenticationInfo createAuthenticationInfo(UsernamePasswordToken token, AuthenticationResult result) { - User user = result.getUser(); - Collection groups = authenticate(requestProvider.get(), new String(token.getPassword()), result); - + /** + * Creates authentication info from token and authentication result. + * + * @param token username and password token + * @param authenticationResult authentication result + * + * @return authentication info + */ + public AuthenticationInfo createAuthenticationInfo( + UsernamePasswordToken token, AuthenticationResult authenticationResult + ) { + User user = authenticationResult.getUser(); + Set groups = groupCollector.collectGroups(authenticationResult); + + synchronizer.synchronize(user, groups); + + if (isUserIsDisabled(user)) { + throwAccountIsDisabledExceptionAndLog(user.getName()); + } + + PrincipalCollection collection = createPrincipalCollection(user, groups); + + AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(collection, token.getPassword()); + sessionStore.store(token); + return authenticationInfo; + } + + private PrincipalCollection createPrincipalCollection(User user, Set groups) { SimplePrincipalCollection collection = new SimplePrincipalCollection(); - - /* - * the first (primary) principal should be a unique identifier - */ collection.add(user.getId(), ScmRealm.NAME); collection.add(user, ScmRealm.NAME); collection.add(new GroupNames(groups), ScmRealm.NAME); - - return new SimpleAuthenticationInfo(collection, token.getPassword()); + return collection; } + private boolean isUserIsDisabled(User user) { + return !user.isActive(); + } - private Set authenticate(HttpServletRequest request, String password, AuthenticationResult ar) { - Set groupSet = null; - User user = ar.getUser(); - - try - { - groupSet = createGroupSet(ar); - - // check for admin user - checkForAuthenticatedAdmin(user, groupSet); - - // store user - User dbUser = userDAO.get(user.getName()); - - if (dbUser != null) - { - checkDBForAdmin(user, dbUser); - checkDBForActive(user, dbUser); - } - - // create new user - else if (user.isValid()) - { - user.setCreationDate(System.currentTimeMillis()); - - // TODO find a better way - UserEventHack.fireEvent(userManager, user, HandlerEvent.BEFORE_CREATE); - userDAO.add(user); - UserEventHack.fireEvent(userManager, user, HandlerEvent.CREATE); - } - else if (logger.isErrorEnabled()) - { - logger.error("could not create user {}, beacause it is not valid", - user.getName()); - } - - if (user.isActive()) - { - - if (logger.isDebugEnabled()) - { - logGroups(user, groupSet); - } - - // store encrypted credentials in session - String credentials = user.getName(); - - if (Util.isNotEmpty(password)) - { - credentials = credentials.concat(":").concat(password); - } - - credentials = CipherUtil.getInstance().encode(credentials); - request.getSession(true).setAttribute(SCM_CREDENTIALS, credentials); - } - else - { - - String msg = "user ".concat(user.getName()).concat(" is deactivated"); - - if (logger.isWarnEnabled()) - { - logger.warn(msg); - } - - throw new DisabledAccountException(msg); - - } - } - catch (IOException | UserException ex) - { - logger.error("authentication failed", ex); - - throw new AuthenticationException("authentication failed", ex); - } - - return groupSet; + private void throwAccountIsDisabledExceptionAndLog(String username) { + String msg = "user ".concat(username).concat(" is deactivated"); + LOG.warn(msg); + throw new DisabledAccountException(msg); } - - private void checkDBForActive(User user, User dbUser) - { - // user is deactivated by database - if (!dbUser.isActive()) - { - if (logger.isDebugEnabled()) - { - logger.debug("user {} is marked as deactivated by local database", - user.getName()); - } - - user.setActive(false); - } - } - - private void checkDBForAdmin(User user, User dbUser) throws UserException, IOException - { - - // if database user is an admin, set admin for the current user - if (dbUser.isAdmin()) - { - if (logger.isDebugEnabled()) - { - logger.debug("user {} of type {} is marked as admin by local database", - user.getName(), user.getType()); - } - - user.setAdmin(true); - } - - // modify existing user, copy properties except password and admin - if (user.copyProperties(dbUser, false)) - { - user.setLastModified(System.currentTimeMillis()); - UserEventHack.fireEvent(userManager, user, HandlerEvent.BEFORE_MODIFY); - userDAO.modify(user); - UserEventHack.fireEvent(userManager, user, HandlerEvent.MODIFY); - } - } - - private void checkForAuthenticatedAdmin(User user, Set groupSet) - { - if (!user.isAdmin()) - { - user.setAdmin(isAdmin(user, groupSet)); - - if (logger.isDebugEnabled() && user.isAdmin()) - { - logger.debug("user {} is marked as admin by configuration", - user.getName()); - } - } - else if (logger.isDebugEnabled()) - { - logger.debug("authenticator {} marked user {} as admin", user.getType(), - user.getName()); - } - } - - private Set createGroupSet(AuthenticationResult ar) - { - Set groupSet = Sets.newHashSet(); - - // add group for all authenticated users - groupSet.add(GroupNames.AUTHENTICATED); - - // load external groups - Collection extGroups = ar.getGroups(); - - if (extGroups != null) - { - groupSet.addAll(extGroups); - } - - // load internal groups - loadGroups(ar.getUser(), groupSet); - - return groupSet; - } - - private void loadGroups(User user, Set groupSet) - { - Collection groupCollection = groupManager.getGroupsForMember(user.getName()); - - if (groupCollection != null) - { - for (Group group : groupCollection) - { - groupSet.add(group.getName()); - } - } - } - - private void logGroups(User user, Set groups) - { - StringBuilder msg = new StringBuilder("user "); - - msg.append(user.getName()); - - if (Util.isNotEmpty(groups)) - { - msg.append(" is member of "); - - Joiner.on(", ").appendTo(msg, groups); - } - else - { - msg.append(" is not a member of a group"); - } - - logger.debug(msg.toString()); - } - - private boolean isAdmin(User user, Collection groups) - { - boolean result = false; - Set adminUsers = configuration.getAdminUsers(); - - if (adminUsers != null) - { - result = adminUsers.contains(user.getName()); - } - - if (!result) - { - Set adminGroups = configuration.getAdminGroups(); - - if (adminGroups != null) - { - result = Util.containsOne(adminGroups, groups); - } - } - - return result; - } - - } diff --git a/scm-webapp/src/main/java/sonia/scm/security/GroupCollector.java b/scm-webapp/src/main/java/sonia/scm/security/GroupCollector.java index 616351107e..3f1fa31b44 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/GroupCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/GroupCollector.java @@ -30,17 +30,33 @@ */ package sonia.scm.security; +import com.google.common.base.Joiner; +import com.google.common.collect.Sets; import com.google.inject.Inject; +import java.util.Collection; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.group.Group; import sonia.scm.group.GroupManager; +import sonia.scm.group.GroupNames; +import sonia.scm.user.User; +import sonia.scm.util.Util; import sonia.scm.web.security.AuthenticationResult; /** - * + * Collects groups from {@link GroupManager} after authentication. + * * @author Sebastian Sdorra + * @since 1.52 */ public class GroupCollector { + /** + * the logger for GroupCollector + */ + private static final Logger LOG = LoggerFactory.getLogger(GroupCollector.class); + private final GroupManager groupManager; @Inject @@ -48,8 +64,60 @@ public class GroupCollector { this.groupManager = groupManager; } - public Set collectGroups(AuthenticationResult result){ + /** + * Collect groups from {@link AuthenticationResult} and {@link GroupManager}. + * + * @param authenticationResult authentication result + * + * @return collected groups + */ + public Set collectGroups(AuthenticationResult authenticationResult) { + Set groups = Sets.newHashSet(); + + // add group for all authenticated users + groups.add(GroupNames.AUTHENTICATED); + + // load external groups + Collection groupsFromAuthenticator = authenticationResult.getGroups(); + + if (groupsFromAuthenticator != null) { + groups.addAll(groupsFromAuthenticator); + } + + User user = authenticationResult.getUser(); + loadGroupFromDatabase(user, groups); + + if (LOG.isDebugEnabled()) { + LOG.debug(createMembershipLogMessage(user, groups)); + } + return groups; + } + + private void loadGroupFromDatabase(User user, Set groupSet) { + Collection groupCollection = groupManager.getGroupsForMember(user.getName()); + + if (groupCollection != null) { + for (Group group : groupCollection) { + groupSet.add(group.getName()); + } + } + } + + private String createMembershipLogMessage(User user, Set groups) { + StringBuilder msg = new StringBuilder("user "); + + msg.append(user.getName()); + + if (Util.isNotEmpty(groups)) { + msg.append(" is member of "); + + Joiner.on(", ").appendTo(msg, groups); + } else { + msg.append(" is not a member of a group"); + } + + return msg.toString(); } } diff --git a/scm-webapp/src/main/java/sonia/scm/security/LocalDatabaseSynchronizer.java b/scm-webapp/src/main/java/sonia/scm/security/LocalDatabaseSynchronizer.java new file mode 100644 index 0000000000..af99ce5609 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/security/LocalDatabaseSynchronizer.java @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2014, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ +package sonia.scm.security; + +import com.google.inject.Inject; +import java.util.Set; +import org.apache.shiro.authc.DisabledAccountException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.HandlerEvent; +import sonia.scm.user.User; +import sonia.scm.user.UserDAO; +import sonia.scm.user.UserEventHack; +import sonia.scm.user.UserManager; + +/** + * Checks and synchronizes authenticated users with local database. + * + * @author Sebastian Sdorra + * @since 1.52 + */ +public class LocalDatabaseSynchronizer { + + /** + * the logger for LocalDatabaseSynchronizer + */ + private static final Logger logger = LoggerFactory.getLogger(LocalDatabaseSynchronizer.class); + + private final AdminDetector adminSelector; + private final UserManager userManager; + private final UserDAO userDAO; + + @Inject + public LocalDatabaseSynchronizer(AdminDetector adminSelector, UserManager userManager, UserDAO userDAO) { + this.adminSelector = adminSelector; + this.userManager = userManager; + this.userDAO = userDAO; + } + + /** + * Check for disabled and administrator marks on authenticated users and synchronize the state with the local + * database. + * + * @param user authenticated user + * @param groups groups of authenticated user + */ + public void synchronize(User user, Set groups) { + adminSelector.checkForAuthenticatedAdmin(user, groups); + + User dbUser = userDAO.get(user.getId()); + if (dbUser != null) { + synchronizeWithLocalDatabase(user, dbUser); + } else if (user.isValid()) { + createUserInLocalDatabase(user); + } else { + logger.warn("could not create user {}, beacause it is not valid", user.getName()); + } + } + + private void synchronizeWithLocalDatabase(User user, User dbUser) { + synchronizeAdminFlag(user, dbUser); + synchronizeActiveFlag(user, dbUser); + modifyUserInLocalDatabase(user, dbUser); + } + + private void synchronizeAdminFlag(User user, User dbUser) { + // if database user is an admin, set admin for the current user + if (dbUser.isAdmin()) { + logger.debug("user {} of type {} is marked as admin by local database", user.getName(), user.getType()); + user.setAdmin(true); + } + } + + private void synchronizeActiveFlag(User user, User dbUser) { + // user is deactivated by database + if (!dbUser.isActive()) { + logger.debug("user {} is marked as deactivated by local database", user.getName()); + user.setActive(false); + } + } + + private void createUserInLocalDatabase(User user) { + user.setCreationDate(System.currentTimeMillis()); + UserEventHack.fireEvent(userManager, user, HandlerEvent.BEFORE_CREATE); + userDAO.add(user); + UserEventHack.fireEvent(userManager, user, HandlerEvent.CREATE); + } + + private void modifyUserInLocalDatabase(User user, User dbUser) { + // modify existing user, copy properties except password and admin + if (user.copyProperties(dbUser, false)) { + user.setLastModified(System.currentTimeMillis()); + UserEventHack.fireEvent(userManager, user, HandlerEvent.BEFORE_MODIFY); + userDAO.modify(user); + UserEventHack.fireEvent(userManager, user, HandlerEvent.MODIFY); + } + } + +} diff --git a/scm-webapp/src/main/java/sonia/scm/security/SessionStore.java b/scm-webapp/src/main/java/sonia/scm/security/SessionStore.java new file mode 100644 index 0000000000..88ae3c0912 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/security/SessionStore.java @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2014, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ +package sonia.scm.security; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import javax.servlet.http.HttpServletRequest; +import org.apache.shiro.authc.UsernamePasswordToken; + +/** + * + * @author Sebastian Sdorra + */ +public class SessionStore { + + private static final String SCM_CREDENTIALS = "SCM_CREDENTIALS"; + + private final Provider requestProvider; + + @Inject + public SessionStore(Provider requestProvider) { + this.requestProvider = requestProvider; + } + + public void store(UsernamePasswordToken token) { + // store encrypted credentials in session + String credentials = token.getUsername(); + + char[] password = token.getPassword(); + if (password != null && password.length > 0) { + credentials = credentials.concat(":").concat(new String(password)); + } + + credentials = CipherUtil.getInstance().encode(credentials); + requestProvider.get().getSession(true).setAttribute(SCM_CREDENTIALS, credentials); + } + +} diff --git a/scm-webapp/src/test/java/sonia/scm/security/ScmRealmTest.java b/scm-webapp/src/test/java/sonia/scm/security/ScmRealmTest.java index 692a9493c7..42ea65e125 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/ScmRealmTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/ScmRealmTest.java @@ -479,12 +479,18 @@ public class ScmRealmTest CacheManager cacheManager = new MapCacheManager(); + AdminDetector adminSelector = new AdminDetector(new ScmConfiguration()); + LocalDatabaseSynchronizer synchronizer = new LocalDatabaseSynchronizer( + adminSelector, userManager, userDAO + ); + + GroupCollector groupCollector = new GroupCollector(groupManager); + SessionStore sessionStore = new SessionStore(requestProvider); + AuthenticationInfoCollector authcCollector = new AuthenticationInfoCollector( - new ScmConfiguration(), - userManager, - groupManager, - userDAO, - requestProvider + synchronizer, + groupCollector, + sessionStore ); AuthorizationCollector authzCollector = new AuthorizationCollector(