mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 00:15:44 +01:00
#781 process all kinds authorization relevant event and produce AuthorizationChangedEvent
This commit is contained in:
@@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* 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 sonia.scm.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This type of event is fired whenever a authorization relevant data changes. This event
|
||||||
|
* is especially useful for cache invalidation.
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
* @since 1.52
|
||||||
|
*/
|
||||||
|
@Event
|
||||||
|
public final class AuthorizationChangedEvent {
|
||||||
|
|
||||||
|
private final String nameOfAffectedUser;
|
||||||
|
|
||||||
|
private AuthorizationChangedEvent(String nameOfAffectedUser) {
|
||||||
|
this.nameOfAffectedUser = nameOfAffectedUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if every user is affected by this data change.
|
||||||
|
*
|
||||||
|
* @return {@code true} if every user is affected
|
||||||
|
*/
|
||||||
|
public boolean isEveryUserAffected(){
|
||||||
|
return nameOfAffectedUser != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the user which is affected by this event.
|
||||||
|
*
|
||||||
|
* @return name of affected user
|
||||||
|
*/
|
||||||
|
public String getNameOfAffectedUser(){
|
||||||
|
return nameOfAffectedUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new event which affects every user.
|
||||||
|
*
|
||||||
|
* @return new event for every user
|
||||||
|
*/
|
||||||
|
public static AuthorizationChangedEvent createForEveryUser() {
|
||||||
|
return new AuthorizationChangedEvent(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event which affect a single user.
|
||||||
|
*
|
||||||
|
* @param nameOfAffectedUser name of affected user
|
||||||
|
*
|
||||||
|
* @return new event for a single user
|
||||||
|
*/
|
||||||
|
public static AuthorizationChangedEvent createForUser(String nameOfAffectedUser) {
|
||||||
|
return new AuthorizationChangedEvent(nameOfAffectedUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -166,6 +166,7 @@ import sonia.scm.net.ahc.JsonContentTransformer;
|
|||||||
import sonia.scm.net.ahc.XmlContentTransformer;
|
import sonia.scm.net.ahc.XmlContentTransformer;
|
||||||
import sonia.scm.schedule.QuartzScheduler;
|
import sonia.scm.schedule.QuartzScheduler;
|
||||||
import sonia.scm.schedule.Scheduler;
|
import sonia.scm.schedule.Scheduler;
|
||||||
|
import sonia.scm.security.AuthorizationChangedEventProducer;
|
||||||
import sonia.scm.security.XsrfProtectionFilter;
|
import sonia.scm.security.XsrfProtectionFilter;
|
||||||
import sonia.scm.web.UserAgentParser;
|
import sonia.scm.web.UserAgentParser;
|
||||||
|
|
||||||
@@ -300,6 +301,7 @@ public class ScmServletModule extends ServletModule
|
|||||||
pluginLoader.processExtensions(binder());
|
pluginLoader.processExtensions(binder());
|
||||||
|
|
||||||
// bind security stuff
|
// bind security stuff
|
||||||
|
bind(AuthorizationChangedEventProducer.class);
|
||||||
bind(PermissionResolver.class, RepositoryPermissionResolver.class);
|
bind(PermissionResolver.class, RepositoryPermissionResolver.class);
|
||||||
bind(AuthenticationManager.class, ChainAuthenticatonManager.class);
|
bind(AuthenticationManager.class, ChainAuthenticatonManager.class);
|
||||||
bind(SecurityContext.class).to(BasicSecurityContext.class);
|
bind(SecurityContext.class).to(BasicSecurityContext.class);
|
||||||
@@ -310,6 +312,7 @@ public class ScmServletModule extends ServletModule
|
|||||||
|
|
||||||
// bind cache
|
// bind cache
|
||||||
bind(CacheManager.class, GuavaCacheManager.class);
|
bind(CacheManager.class, GuavaCacheManager.class);
|
||||||
|
bind(org.apache.shiro.cache.CacheManager.class, GuavaCacheManager.class);
|
||||||
|
|
||||||
// bind dao
|
// bind dao
|
||||||
bind(GroupDAO.class, XmlGroupDAO.class);
|
bind(GroupDAO.class, XmlGroupDAO.class);
|
||||||
@@ -386,8 +389,7 @@ public class ScmServletModule extends ServletModule
|
|||||||
filter(PATTERN_ALL).through(BaseUrlFilter.class);
|
filter(PATTERN_ALL).through(BaseUrlFilter.class);
|
||||||
filter(PATTERN_ALL).through(AutoLoginFilter.class);
|
filter(PATTERN_ALL).through(AutoLoginFilter.class);
|
||||||
filterRegex(RESOURCE_REGEX).through(GZipFilter.class);
|
filterRegex(RESOURCE_REGEX).through(GZipFilter.class);
|
||||||
filter(PATTERN_RESTAPI,
|
filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(ApiBasicAuthenticationFilter.class);
|
||||||
PATTERN_DEBUG).through(ApiBasicAuthenticationFilter.class);
|
|
||||||
filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(SecurityFilter.class);
|
filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(SecurityFilter.class);
|
||||||
filter(PATTERN_CONFIG, PATTERN_ADMIN).through(AdminSecurityFilter.class);
|
filter(PATTERN_CONFIG, PATTERN_ADMIN).through(AdminSecurityFilter.class);
|
||||||
|
|
||||||
@@ -434,11 +436,7 @@ public class ScmServletModule extends ServletModule
|
|||||||
UriExtensionsConfig.class.getName());
|
UriExtensionsConfig.class.getName());
|
||||||
|
|
||||||
String restPath = getRestPackages();
|
String restPath = getRestPackages();
|
||||||
|
logger.info("configure jersey with package path: {}", restPath);
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("configure jersey with package path: {}", restPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
params.put(PackagesResourceConfig.PROPERTY_PACKAGES, restPath);
|
params.put(PackagesResourceConfig.PROPERTY_PACKAGES, restPath);
|
||||||
serve(PATTERN_RESTAPI).with(GuiceContainer.class, params);
|
serve(PATTERN_RESTAPI).with(GuiceContainer.class, params);
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public class AuthenticationInfoCollector {
|
|||||||
|
|
||||||
synchronizer.synchronize(user, groups);
|
synchronizer.synchronize(user, groups);
|
||||||
|
|
||||||
if (isUserIsDisabled(user)) {
|
if (isUserDisabled(user)) {
|
||||||
throwAccountIsDisabledExceptionAndLog(user.getName());
|
throwAccountIsDisabledExceptionAndLog(user.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ public class AuthenticationInfoCollector {
|
|||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isUserIsDisabled(User user) {
|
private boolean isUserDisabled(User user) {
|
||||||
return !user.isActive();
|
return !user.isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,271 @@
|
|||||||
|
/**
|
||||||
|
* 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.common.annotations.VisibleForTesting;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import sonia.scm.EagerSingleton;
|
||||||
|
import sonia.scm.ModificationHandlerEvent;
|
||||||
|
import sonia.scm.event.HandlerEventBase;
|
||||||
|
import sonia.scm.event.ScmEventBus;
|
||||||
|
import sonia.scm.group.Group;
|
||||||
|
import sonia.scm.group.GroupEvent;
|
||||||
|
import sonia.scm.group.GroupModificationEvent;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.RepositoryEvent;
|
||||||
|
import sonia.scm.repository.RepositoryModificationEvent;
|
||||||
|
import sonia.scm.user.User;
|
||||||
|
import sonia.scm.user.UserEvent;
|
||||||
|
import sonia.scm.user.UserModificationEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives all kinds of events, which affects authorization relevant data and fires an
|
||||||
|
* {@link AuthorizationChangedEvent} if authorization data has changed.
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
* @since 1.52
|
||||||
|
*/
|
||||||
|
@EagerSingleton
|
||||||
|
public class AuthorizationChangedEventProducer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the logger for AuthorizationChangedEventProducer
|
||||||
|
*/
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AuthorizationChangedEventProducer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance.
|
||||||
|
*/
|
||||||
|
public AuthorizationChangedEventProducer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the cache of a user which was modified. The cache entries for the user will be invalidated for the
|
||||||
|
* following reasons:
|
||||||
|
* <ul>
|
||||||
|
* <li>Admin or Active flag was modified.</li>
|
||||||
|
* <li>New user created, for the case of old cache values</li>
|
||||||
|
* <li>User deleted</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param event user event
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void onEvent(UserEvent event) {
|
||||||
|
if (event.getEventType().isPost()) {
|
||||||
|
if (isModificationEvent(event)) {
|
||||||
|
handleUserModificationEvent((UserModificationEvent) event);
|
||||||
|
} else {
|
||||||
|
handleUserEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isModificationEvent(HandlerEventBase<?> event) {
|
||||||
|
return event instanceof ModificationHandlerEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUserEvent(UserEvent event) {
|
||||||
|
String username = event.getItem().getName();
|
||||||
|
logger.debug(
|
||||||
|
"fire authorization changed event for user {}, because of user {} event", username, event.getEventType()
|
||||||
|
);
|
||||||
|
fireEventForUser(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUserModificationEvent(UserModificationEvent event) {
|
||||||
|
String username = event.getItem().getId();
|
||||||
|
User beforeModification = event.getItemBeforeModification();
|
||||||
|
if (isAuthorizationDataModified(event.getItem(), beforeModification)) {
|
||||||
|
logger.debug(
|
||||||
|
"fire authorization changed event for user {}, because of a authorization relevant field has changed",
|
||||||
|
username
|
||||||
|
);
|
||||||
|
fireEventForUser(username);
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
"authorization changed event for user {} is not fired, because no authorization relevant field has changed",
|
||||||
|
username
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAuthorizationDataModified(User user, User beforeModification) {
|
||||||
|
return user.isAdmin() != beforeModification.isAdmin() || user.isActive() != beforeModification.isActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fireEventForUser(String username) {
|
||||||
|
sendEvent(AuthorizationChangedEvent.createForUser(username));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the whole cache, if a repository has changed. The cache get cleared for one of the following reasons:
|
||||||
|
* <ul>
|
||||||
|
* <li>New repository created</li>
|
||||||
|
* <li>Repository was removed</li>
|
||||||
|
* <li>Archived, Public readable or permission field of the repository was modified</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param event repository event
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void onEvent(RepositoryEvent event) {
|
||||||
|
if (event.getEventType().isPost()) {
|
||||||
|
if (isModificationEvent(event)) {
|
||||||
|
handleRepositoryModificationEvent((RepositoryModificationEvent) event);
|
||||||
|
} else {
|
||||||
|
handleRepositoryEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRepositoryModificationEvent(RepositoryModificationEvent event) {
|
||||||
|
Repository repository = event.getItem();
|
||||||
|
if (isAuthorizationDataModified(repository, event.getItemBeforeModification())) {
|
||||||
|
logger.debug(
|
||||||
|
"fire authorization changed event, because a relevant field of repository {} has changed", repository.getName()
|
||||||
|
);
|
||||||
|
fireEventForEveryUser();
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
"authorization changed event is not fired, because non relevant field of repository {} has changed",
|
||||||
|
repository.getName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAuthorizationDataModified(Repository repository, Repository beforeModification) {
|
||||||
|
return repository.isArchived() != beforeModification.isArchived()
|
||||||
|
|| repository.isPublicReadable() != beforeModification.isPublicReadable()
|
||||||
|
|| ! repository.getPermissions().equals(beforeModification.getPermissions());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fireEventForEveryUser() {
|
||||||
|
sendEvent(AuthorizationChangedEvent.createForEveryUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRepositoryEvent(RepositoryEvent event){
|
||||||
|
logger.debug(
|
||||||
|
"fire authorization changed event, because of received {} event for repository {}",
|
||||||
|
event.getEventType(), event.getItem().getName()
|
||||||
|
);
|
||||||
|
fireEventForEveryUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the whole cache if a group permission has changed and invalidates the cached entries of a user, if a
|
||||||
|
* user permission has changed.
|
||||||
|
*
|
||||||
|
* @param event permission event
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void onEvent(StoredAssignedPermissionEvent event) {
|
||||||
|
if (event.getEventType().isPost()) {
|
||||||
|
StoredAssignedPermission permission = event.getPermission();
|
||||||
|
if (permission.isGroupPermission()) {
|
||||||
|
handleGroupPermissionChange(permission);
|
||||||
|
} else {
|
||||||
|
handleUserPermissionChange(permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleGroupPermissionChange(StoredAssignedPermission permission) {
|
||||||
|
logger.debug(
|
||||||
|
"fire authorization changed event, because global group permission {} has changed",
|
||||||
|
permission.getId()
|
||||||
|
);
|
||||||
|
fireEventForEveryUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUserPermissionChange(StoredAssignedPermission permission) {
|
||||||
|
logger.debug(
|
||||||
|
"fire authorization changed event for user {}, because permission {} has changed",
|
||||||
|
permission.getName(), permission.getId()
|
||||||
|
);
|
||||||
|
fireEventForUser(permission.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the whole cache, if a group has changed. The cache get cleared for one of the following reasons:
|
||||||
|
* <ul>
|
||||||
|
* <li>New group created</li>
|
||||||
|
* <li>Group was removed</li>
|
||||||
|
* <li>Group members was modified</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param event group event
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void onEvent(GroupEvent event) {
|
||||||
|
if (event.getEventType().isPost()) {
|
||||||
|
if (isModificationEvent(event)) {
|
||||||
|
handleGroupModificationEvent((GroupModificationEvent) event);
|
||||||
|
} else {
|
||||||
|
handleGroupEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleGroupModificationEvent(GroupModificationEvent event) {
|
||||||
|
Group group = event.getItem();
|
||||||
|
if (isAuthorizationDataModified(group, event.getItemBeforeModification())) {
|
||||||
|
logger.debug("fire authorization changed event, because group {} has changed", group.getId());
|
||||||
|
fireEventForEveryUser();
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
"authorization changed event is not fired, because non relevant field of group {} has changed",
|
||||||
|
group.getId()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAuthorizationDataModified(Group group, Group beforeModification) {
|
||||||
|
return !group.getMembers().equals(beforeModification.getMembers());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleGroupEvent(GroupEvent event){
|
||||||
|
logger.debug(
|
||||||
|
"fire authorization changed event, because of received group event {} for group {}",
|
||||||
|
event.getEventType(),
|
||||||
|
event.getItem().getId()
|
||||||
|
);
|
||||||
|
fireEventForEveryUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void sendEvent(AuthorizationChangedEvent event) {
|
||||||
|
ScmEventBus.getInstance().post(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -57,14 +57,11 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import sonia.scm.cache.Cache;
|
import sonia.scm.cache.Cache;
|
||||||
import sonia.scm.cache.CacheManager;
|
import sonia.scm.cache.CacheManager;
|
||||||
import sonia.scm.group.GroupEvent;
|
|
||||||
import sonia.scm.group.GroupNames;
|
import sonia.scm.group.GroupNames;
|
||||||
import sonia.scm.repository.PermissionType;
|
import sonia.scm.repository.PermissionType;
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
import sonia.scm.repository.RepositoryDAO;
|
import sonia.scm.repository.RepositoryDAO;
|
||||||
import sonia.scm.repository.RepositoryEvent;
|
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserEvent;
|
|
||||||
import sonia.scm.util.Util;
|
import sonia.scm.util.Util;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
@@ -72,10 +69,6 @@ import sonia.scm.util.Util;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import sonia.scm.Filter;
|
import sonia.scm.Filter;
|
||||||
import sonia.scm.group.Group;
|
|
||||||
import sonia.scm.group.GroupModificationEvent;
|
|
||||||
import sonia.scm.repository.RepositoryModificationEvent;
|
|
||||||
import sonia.scm.user.UserModificationEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -114,8 +107,7 @@ public class AuthorizationCollector
|
|||||||
RepositoryDAO repositoryDAO, SecuritySystem securitySystem,
|
RepositoryDAO repositoryDAO, SecuritySystem securitySystem,
|
||||||
PermissionResolver resolver)
|
PermissionResolver resolver)
|
||||||
{
|
{
|
||||||
this.cache = cacheManager.getCache(CacheKey.class, AuthorizationInfo.class,
|
this.cache = cacheManager.getCache(CacheKey.class, AuthorizationInfo.class, CACHE_NAME);
|
||||||
CACHE_NAME);
|
|
||||||
this.repositoryDAO = repositoryDAO;
|
this.repositoryDAO = repositoryDAO;
|
||||||
this.securitySystem = securitySystem;
|
this.securitySystem = securitySystem;
|
||||||
this.resolver = resolver;
|
this.resolver = resolver;
|
||||||
@@ -146,189 +138,9 @@ public class AuthorizationCollector
|
|||||||
return authorizationInfo;
|
return authorizationInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates the cache of a user which was modified. The cache entries for the user will be invalidated for the
|
|
||||||
* following reasons:
|
|
||||||
* <ul>
|
|
||||||
* <li>Admin or Active flag was modified.</li>
|
|
||||||
* <li>New user created, for the case of old cache values</li>
|
|
||||||
* <li>User deleted</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param event user event
|
|
||||||
*/
|
|
||||||
@Subscribe
|
|
||||||
public void onEvent(UserEvent event)
|
|
||||||
{
|
|
||||||
if (event.getEventType().isPost())
|
|
||||||
{
|
|
||||||
User user = event.getItem();
|
|
||||||
String username = user.getId();
|
|
||||||
if (event instanceof UserModificationEvent)
|
|
||||||
{
|
|
||||||
User beforeModification = ((UserModificationEvent) event).getItemBeforeModification();
|
|
||||||
if (shouldCacheBeCleared(user, beforeModification))
|
|
||||||
{
|
|
||||||
logger.debug("invalidate cache of user {}, because of a permission relevant field has changed", username);
|
|
||||||
invalidateUserCache(username);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug("cache of user {} is not invalidated, because no permission relevant field has changed", username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug("invalidate cache of user {}, because of user {} event", username, event.getEventType());
|
|
||||||
invalidateUserCache(username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldCacheBeCleared(User user, User beforeModification)
|
|
||||||
{
|
|
||||||
return user.isAdmin() != beforeModification.isAdmin() || user.isActive() != beforeModification.isActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void invalidateUserCache(final String username)
|
|
||||||
{
|
|
||||||
cache.removeAll(new Filter<CacheKey>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean accept(CacheKey item)
|
|
||||||
{
|
|
||||||
return username.equalsIgnoreCase(item.username);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates the whole cache, if a repository has changed. The cache get cleared for one of the following reasons:
|
|
||||||
* <ul>
|
|
||||||
* <li>New repository created</li>
|
|
||||||
* <li>Repository was removed</li>
|
|
||||||
* <li>Archived, Public readable or permission field of the repository was modified</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param event repository event
|
|
||||||
*/
|
|
||||||
@Subscribe
|
|
||||||
public void onEvent(RepositoryEvent event)
|
|
||||||
{
|
|
||||||
if (event.getEventType().isPost())
|
|
||||||
{
|
|
||||||
Repository repository = event.getItem();
|
|
||||||
|
|
||||||
if (event instanceof RepositoryModificationEvent)
|
|
||||||
{
|
|
||||||
Repository beforeModification = ((RepositoryModificationEvent) event).getItemBeforeModification();
|
|
||||||
if (shouldCacheBeCleared(repository, beforeModification))
|
|
||||||
{
|
|
||||||
logger.debug("clear cache, because a relevant field of repository {} has changed", repository.getName());
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug(
|
|
||||||
"cache is not invalidated, because non relevant field of repository {} has changed",
|
|
||||||
repository.getName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug("clear cache, received {} event of repository {}", event.getEventType(), repository.getName());
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldCacheBeCleared(Repository repository, Repository beforeModification)
|
|
||||||
{
|
|
||||||
return repository.isArchived() != beforeModification.isArchived()
|
|
||||||
|| repository.isPublicReadable() != beforeModification.isPublicReadable()
|
|
||||||
|| ! repository.getPermissions().equals(beforeModification.getPermissions());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates the whole cache if a group permission has changed and invalidates the cached entries of a user, if a
|
|
||||||
* user permission has changed.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param event permission event
|
|
||||||
*/
|
|
||||||
@Subscribe
|
|
||||||
public void onEvent(StoredAssignedPermissionEvent event)
|
|
||||||
{
|
|
||||||
if (event.getEventType().isPost())
|
|
||||||
{
|
|
||||||
StoredAssignedPermission permission = event.getPermission();
|
|
||||||
if (permission.isGroupPermission())
|
|
||||||
{
|
|
||||||
logger.debug("clear cache, because global group permission {} has changed", permission.getId());
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug(
|
|
||||||
"clear cache of user {}, because permission {} has changed",
|
|
||||||
permission.getName(), event.getPermission().getId()
|
|
||||||
);
|
|
||||||
invalidateUserCache(permission.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates the whole cache, if a group has changed. The cache get cleared for one of the following reasons:
|
|
||||||
* <ul>
|
|
||||||
* <li>New group created</li>
|
|
||||||
* <li>Group was removed</li>
|
|
||||||
* <li>Group members was modified</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param event group event
|
|
||||||
*/
|
|
||||||
@Subscribe
|
|
||||||
public void onEvent(GroupEvent event)
|
|
||||||
{
|
|
||||||
if (event.getEventType().isPost())
|
|
||||||
{
|
|
||||||
Group group = event.getItem();
|
|
||||||
if (event instanceof GroupModificationEvent)
|
|
||||||
{
|
|
||||||
Group beforeModification = ((GroupModificationEvent) event).getItemBeforeModification();
|
|
||||||
if (shouldCacheBeCleared(group, beforeModification))
|
|
||||||
{
|
|
||||||
logger.debug("clear cache, because group {} has changed", group.getId());
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug(
|
|
||||||
"cache is not invalidated, because non relevant field of group {} has changed",
|
|
||||||
group.getId()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug("clear cache, received group event {} for group {}", event.getEventType(), group.getId());
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldCacheBeCleared(Group group, Group beforeModification)
|
|
||||||
{
|
|
||||||
return !group.getMembers().equals(beforeModification.getMembers());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param principals
|
* @param principals
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
@@ -568,6 +380,30 @@ public class AuthorizationCollector
|
|||||||
//J+
|
//J+
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void invalidateCache(AuthorizationChangedEvent event) {
|
||||||
|
if (event.isEveryUserAffected()) {
|
||||||
|
invalidateUserCache(event.getNameOfAffectedUser());
|
||||||
|
} else {
|
||||||
|
invalidateCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invalidateUserCache(final String username) {
|
||||||
|
logger.info("invalidate cache for user {}, because of a received authorization event", username);
|
||||||
|
cache.removeAll(new Filter<CacheKey>() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(CacheKey item) {
|
||||||
|
return username.equalsIgnoreCase(item.username);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invalidateCache() {
|
||||||
|
logger.info("invalidate cache, because of a received authorization event");
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
//~--- inner classes --------------------------------------------------------
|
//~--- inner classes --------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ package sonia.scm.security;
|
|||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
@@ -46,9 +47,11 @@ import org.apache.shiro.authc.UnknownAccountException;
|
|||||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||||
import org.apache.shiro.authc.pam.UnsupportedTokenException;
|
import org.apache.shiro.authc.pam.UnsupportedTokenException;
|
||||||
import org.apache.shiro.authz.AuthorizationInfo;
|
import org.apache.shiro.authz.AuthorizationInfo;
|
||||||
|
import org.apache.shiro.cache.CacheManager;
|
||||||
import org.apache.shiro.realm.AuthorizingRealm;
|
import org.apache.shiro.realm.AuthorizingRealm;
|
||||||
import org.apache.shiro.subject.PrincipalCollection;
|
import org.apache.shiro.subject.PrincipalCollection;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.web.security.AuthenticationResult;
|
import sonia.scm.web.security.AuthenticationResult;
|
||||||
import sonia.scm.web.security.AuthenticationState;
|
import sonia.scm.web.security.AuthenticationState;
|
||||||
|
|
||||||
@@ -63,6 +66,11 @@ import sonia.scm.web.security.AuthenticationState;
|
|||||||
@Singleton
|
@Singleton
|
||||||
public class ScmRealm extends AuthorizingRealm {
|
public class ScmRealm extends AuthorizingRealm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the logger for ScmRealm
|
||||||
|
*/
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ScmRealm.class);
|
||||||
|
|
||||||
public static final String NAME = "scm";
|
public static final String NAME = "scm";
|
||||||
|
|
||||||
|
|
||||||
@@ -74,32 +82,35 @@ public class ScmRealm extends AuthorizingRealm {
|
|||||||
/**
|
/**
|
||||||
* Constructs a new scm realm.
|
* Constructs a new scm realm.
|
||||||
*
|
*
|
||||||
|
* @param cacheManager cache manager
|
||||||
* @param authenticator authenticator facade
|
* @param authenticator authenticator facade
|
||||||
* @param loginAttemptHandler login attempt handler
|
* @param loginAttemptHandler login attempt handler
|
||||||
* @param authcCollector authentication info collector
|
* @param authcCollector authentication info collector
|
||||||
* @param authzCollector authorization collector
|
* @param authzCollector authorization collector
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public ScmRealm(AuthenticatorFacade authenticator, LoginAttemptHandler loginAttemptHandler,
|
public ScmRealm(CacheManager cacheManager,
|
||||||
|
AuthenticatorFacade authenticator, LoginAttemptHandler loginAttemptHandler,
|
||||||
AuthenticationInfoCollector authcCollector, AuthorizationCollector authzCollector) {
|
AuthenticationInfoCollector authcCollector, AuthorizationCollector authzCollector) {
|
||||||
|
super(cacheManager);
|
||||||
|
|
||||||
this.authenticator = authenticator;
|
this.authenticator = authenticator;
|
||||||
this.loginAttemptHandler = loginAttemptHandler;
|
this.loginAttemptHandler = loginAttemptHandler;
|
||||||
this.authcCollector = authcCollector;
|
this.authcCollector = authcCollector;
|
||||||
this.authzCollector = authzCollector;
|
this.authzCollector = authzCollector;
|
||||||
|
|
||||||
|
|
||||||
// set token class
|
// set token class
|
||||||
setAuthenticationTokenClass(UsernamePasswordToken.class);
|
setAuthenticationTokenClass(UsernamePasswordToken.class);
|
||||||
|
|
||||||
// use own custom caching
|
|
||||||
setCachingEnabled(false);
|
|
||||||
setAuthenticationCachingEnabled(false);
|
|
||||||
setAuthorizationCachingEnabled(false);
|
|
||||||
|
|
||||||
// set components
|
// set components
|
||||||
setPermissionResolver(new RepositoryPermissionResolver());
|
setPermissionResolver(new RepositoryPermissionResolver());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
|
||||||
|
return principals.getPrimaryPrincipal();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
|
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
|
||||||
UsernamePasswordToken token = castToken(authToken);
|
UsernamePasswordToken token = castToken(authToken);
|
||||||
@@ -138,4 +149,23 @@ public class ScmRealm extends AuthorizingRealm {
|
|||||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
|
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
|
||||||
return authzCollector.collect(principals);
|
return authzCollector.collect(principals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void invalidateCache(AuthorizationChangedEvent event) {
|
||||||
|
if (event.isEveryUserAffected()) {
|
||||||
|
invalidateUserCache(event.getNameOfAffectedUser());
|
||||||
|
} else {
|
||||||
|
invalidateCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invalidateUserCache(final String username) {
|
||||||
|
logger.info("invalidate cache for user {}, because of a received authorization event", username);
|
||||||
|
getAuthorizationCache().remove(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invalidateCache() {
|
||||||
|
logger.info("invalidate cache, because of a received authorization event");
|
||||||
|
getAuthorizationCache().clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,8 +72,11 @@ import sonia.scm.security.SecuritySystem;
|
|||||||
import sonia.scm.user.UserTestData;
|
import sonia.scm.user.UserTestData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Performance test for {@link RepositoryManager#getAll()}.
|
||||||
*
|
*
|
||||||
|
* @see <a href="https://goo.gl/PD1AeM">Issue 781</a>
|
||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
|
* @since 1.52
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class DefaultRepositoryManagerPerfTest {
|
public class DefaultRepositoryManagerPerfTest {
|
||||||
@@ -105,6 +108,9 @@ public class DefaultRepositoryManagerPerfTest {
|
|||||||
|
|
||||||
private AuthorizationCollector authzCollector;
|
private AuthorizationCollector authzCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup object under test.
|
||||||
|
*/
|
||||||
@Before
|
@Before
|
||||||
public void setUpObjectUnderTest(){
|
public void setUpObjectUnderTest(){
|
||||||
when(repositoryHandler.getType()).thenReturn(new Type(REPOSITORY_TYPE, REPOSITORY_TYPE));
|
when(repositoryHandler.getType()).thenReturn(new Type(REPOSITORY_TYPE, REPOSITORY_TYPE));
|
||||||
@@ -132,11 +138,17 @@ public class DefaultRepositoryManagerPerfTest {
|
|||||||
ThreadContext.bind(securityManager);
|
ThreadContext.bind(securityManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tear down test objects.
|
||||||
|
*/
|
||||||
@After
|
@After
|
||||||
public void tearDown(){
|
public void tearDown(){
|
||||||
ThreadContext.unbindSecurityManager();
|
ThreadContext.unbindSecurityManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start performance test and ensure that the timeout is not reached.
|
||||||
|
*/
|
||||||
@Test(timeout = 6000l)
|
@Test(timeout = 6000l)
|
||||||
public void perfTestGetAll(){
|
public void perfTestGetAll(){
|
||||||
SecurityUtils.getSubject().login(new UsernamePasswordToken("trillian", "secret"));
|
SecurityUtils.getSubject().login(new UsernamePasswordToken("trillian", "secret"));
|
||||||
|
|||||||
@@ -0,0 +1,256 @@
|
|||||||
|
/**
|
||||||
|
* 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.common.collect.Lists;
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import org.junit.Before;
|
||||||
|
import sonia.scm.HandlerEvent;
|
||||||
|
import sonia.scm.group.Group;
|
||||||
|
import sonia.scm.group.GroupEvent;
|
||||||
|
import sonia.scm.group.GroupModificationEvent;
|
||||||
|
import sonia.scm.repository.PermissionType;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.RepositoryEvent;
|
||||||
|
import sonia.scm.repository.RepositoryModificationEvent;
|
||||||
|
import sonia.scm.repository.RepositoryTestData;
|
||||||
|
import sonia.scm.user.User;
|
||||||
|
import sonia.scm.user.UserEvent;
|
||||||
|
import sonia.scm.user.UserModificationEvent;
|
||||||
|
import sonia.scm.user.UserTestData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link AuthorizationChangedEventProducer}.
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*/
|
||||||
|
public class AuthorizationChangedEventProducerTest {
|
||||||
|
|
||||||
|
private StoringAuthorizationChangedEventProducer producer;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUpProducer() {
|
||||||
|
producer = new StoringAuthorizationChangedEventProducer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.user.UserEvent)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testOnUserEvent()
|
||||||
|
{
|
||||||
|
User user = UserTestData.createDent();
|
||||||
|
producer.onEvent(new UserEvent(user, HandlerEvent.BEFORE_CREATE));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
producer.onEvent(new UserEvent(user, HandlerEvent.CREATE));
|
||||||
|
assertUserEventIsFired("dent");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertEventIsNotFired(){
|
||||||
|
assertNull(producer.event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertUserEventIsFired(String username){
|
||||||
|
assertNotNull(producer.event);
|
||||||
|
assertTrue(producer.event.isEveryUserAffected());
|
||||||
|
assertEquals(username, producer.event.getNameOfAffectedUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.user.UserEvent)} with modified user.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testOnUserModificationEvent()
|
||||||
|
{
|
||||||
|
User user = UserTestData.createDent();
|
||||||
|
User userModified = UserTestData.createDent();
|
||||||
|
userModified.setDisplayName("Super Dent");
|
||||||
|
|
||||||
|
producer.onEvent(new UserModificationEvent(userModified, user, HandlerEvent.BEFORE_CREATE));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
producer.onEvent(new UserModificationEvent(userModified, user, HandlerEvent.CREATE));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
userModified.setAdmin(true);
|
||||||
|
|
||||||
|
producer.onEvent(new UserModificationEvent(userModified, user, HandlerEvent.BEFORE_CREATE));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
producer.onEvent(new UserModificationEvent(userModified, user, HandlerEvent.CREATE));
|
||||||
|
assertUserEventIsFired("dent");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.group.GroupEvent)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testOnGroupEvent()
|
||||||
|
{
|
||||||
|
Group group = new Group("xml", "base");
|
||||||
|
producer.onEvent(new GroupEvent(group, HandlerEvent.BEFORE_CREATE));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
producer.onEvent(new GroupEvent(group, HandlerEvent.CREATE));
|
||||||
|
assertGlobalEventIsFired();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertGlobalEventIsFired(){
|
||||||
|
assertNotNull(producer.event);
|
||||||
|
assertFalse(producer.event.isEveryUserAffected());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.group.GroupEvent)} with modified groups.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testOnGroupModificationEvent()
|
||||||
|
{
|
||||||
|
Group group = new Group("xml", "base");
|
||||||
|
Group modifiedGroup = new Group("xml", "base");
|
||||||
|
producer.onEvent(new GroupModificationEvent(modifiedGroup, group, HandlerEvent.BEFORE_MODIFY));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
producer.onEvent(new GroupModificationEvent(modifiedGroup, group, HandlerEvent.MODIFY));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
modifiedGroup.add("test");
|
||||||
|
producer.onEvent(new GroupModificationEvent(modifiedGroup, group, HandlerEvent.MODIFY));
|
||||||
|
assertGlobalEventIsFired();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.repository.RepositoryEvent)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testOnRepositoryEvent()
|
||||||
|
{
|
||||||
|
Repository repository = RepositoryTestData.createHeartOfGold();
|
||||||
|
producer.onEvent(new RepositoryEvent(repository, HandlerEvent.BEFORE_CREATE));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
producer.onEvent(new RepositoryEvent(repository, HandlerEvent.CREATE));
|
||||||
|
assertGlobalEventIsFired();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.repository.RepositoryEvent)} with modified
|
||||||
|
* repository.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testOnRepositoryModificationEvent()
|
||||||
|
{
|
||||||
|
Repository repositoryModified = RepositoryTestData.createHeartOfGold();
|
||||||
|
repositoryModified.setName("test123");
|
||||||
|
repositoryModified.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test")));
|
||||||
|
|
||||||
|
Repository repository = RepositoryTestData.createHeartOfGold();
|
||||||
|
repository.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test")));
|
||||||
|
|
||||||
|
producer.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.BEFORE_CREATE));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
producer.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
repositoryModified.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test")));
|
||||||
|
producer.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
repositoryModified.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test123")));
|
||||||
|
producer.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
||||||
|
assertGlobalEventIsFired();
|
||||||
|
|
||||||
|
resetStoredEvent();
|
||||||
|
|
||||||
|
repositoryModified.setPermissions(
|
||||||
|
Lists.newArrayList(new sonia.scm.repository.Permission("test", PermissionType.READ, true))
|
||||||
|
);
|
||||||
|
producer.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
||||||
|
assertGlobalEventIsFired();
|
||||||
|
|
||||||
|
resetStoredEvent();
|
||||||
|
|
||||||
|
repositoryModified.setPermissions(
|
||||||
|
Lists.newArrayList(new sonia.scm.repository.Permission("test", PermissionType.WRITE))
|
||||||
|
);
|
||||||
|
producer.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
||||||
|
assertGlobalEventIsFired();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetStoredEvent(){
|
||||||
|
producer.event = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.security.StoredAssignedPermissionEvent)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testOnStoredAssignedPermissionEvent()
|
||||||
|
{
|
||||||
|
StoredAssignedPermission groupPermission = new StoredAssignedPermission(
|
||||||
|
"123", new AssignedPermission("_authenticated", true, "repository:read:*")
|
||||||
|
);
|
||||||
|
producer.onEvent(new StoredAssignedPermissionEvent(HandlerEvent.BEFORE_CREATE, groupPermission));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
producer.onEvent(new StoredAssignedPermissionEvent(HandlerEvent.CREATE, groupPermission));
|
||||||
|
assertGlobalEventIsFired();
|
||||||
|
|
||||||
|
resetStoredEvent();
|
||||||
|
|
||||||
|
StoredAssignedPermission userPermission = new StoredAssignedPermission(
|
||||||
|
"123", new AssignedPermission("trillian", false, "repository:read:*")
|
||||||
|
);
|
||||||
|
producer.onEvent(new StoredAssignedPermissionEvent(HandlerEvent.BEFORE_CREATE, userPermission));
|
||||||
|
assertEventIsNotFired();
|
||||||
|
|
||||||
|
resetStoredEvent();
|
||||||
|
|
||||||
|
producer.onEvent(new StoredAssignedPermissionEvent(HandlerEvent.CREATE, userPermission));
|
||||||
|
assertUserEventIsFired("trillian");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StoringAuthorizationChangedEventProducer extends AuthorizationChangedEventProducer {
|
||||||
|
|
||||||
|
private AuthorizationChangedEvent event;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void sendEvent(AuthorizationChangedEvent event) {
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -54,22 +54,14 @@ import static org.junit.Assert.*;
|
|||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
import sonia.scm.Filter;
|
import sonia.scm.Filter;
|
||||||
import sonia.scm.HandlerEvent;
|
|
||||||
import sonia.scm.cache.Cache;
|
import sonia.scm.cache.Cache;
|
||||||
import sonia.scm.cache.CacheManager;
|
import sonia.scm.cache.CacheManager;
|
||||||
import sonia.scm.group.Group;
|
|
||||||
import sonia.scm.group.GroupEvent;
|
|
||||||
import sonia.scm.group.GroupModificationEvent;
|
|
||||||
import sonia.scm.group.GroupNames;
|
import sonia.scm.group.GroupNames;
|
||||||
import sonia.scm.repository.PermissionType;
|
import sonia.scm.repository.PermissionType;
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
import sonia.scm.repository.RepositoryDAO;
|
import sonia.scm.repository.RepositoryDAO;
|
||||||
import sonia.scm.repository.RepositoryEvent;
|
|
||||||
import sonia.scm.repository.RepositoryModificationEvent;
|
|
||||||
import sonia.scm.repository.RepositoryTestData;
|
import sonia.scm.repository.RepositoryTestData;
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserEvent;
|
|
||||||
import sonia.scm.user.UserModificationEvent;
|
|
||||||
import sonia.scm.user.UserTestData;
|
import sonia.scm.user.UserTestData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,160 +103,6 @@ public class AuthorizationCollectorTest {
|
|||||||
collector = new AuthorizationCollector(cacheManager, repositoryDAO, securitySystem, resolver);
|
collector = new AuthorizationCollector(cacheManager, repositoryDAO, securitySystem, resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.user.UserEvent)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnUserEvent()
|
|
||||||
{
|
|
||||||
User user = UserTestData.createDent();
|
|
||||||
collector.onEvent(new UserEvent(user, HandlerEvent.BEFORE_CREATE));
|
|
||||||
verify(cache, never()).clear();
|
|
||||||
|
|
||||||
collector.onEvent(new UserEvent(user, HandlerEvent.CREATE));
|
|
||||||
verify(cache).removeAll(Mockito.any(Filter.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.user.UserEvent)} with modified user.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnUserModificationEvent()
|
|
||||||
{
|
|
||||||
User user = UserTestData.createDent();
|
|
||||||
User userModified = UserTestData.createDent();
|
|
||||||
userModified.setDisplayName("Super Dent");
|
|
||||||
|
|
||||||
collector.onEvent(new UserModificationEvent(userModified, user, HandlerEvent.BEFORE_CREATE));
|
|
||||||
verify(cache, never()).removeAll(Mockito.any(Filter.class));
|
|
||||||
|
|
||||||
collector.onEvent(new UserModificationEvent(userModified, user, HandlerEvent.CREATE));
|
|
||||||
verify(cache, never()).removeAll(Mockito.any(Filter.class));
|
|
||||||
|
|
||||||
userModified.setAdmin(true);
|
|
||||||
|
|
||||||
collector.onEvent(new UserModificationEvent(userModified, user, HandlerEvent.BEFORE_CREATE));
|
|
||||||
verify(cache, never()).removeAll(Mockito.any(Filter.class));
|
|
||||||
|
|
||||||
collector.onEvent(new UserModificationEvent(userModified, user, HandlerEvent.CREATE));
|
|
||||||
verify(cache).removeAll(Mockito.any(Filter.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.group.GroupEvent)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnGroupEvent()
|
|
||||||
{
|
|
||||||
Group group = new Group("xml", "base");
|
|
||||||
collector.onEvent(new GroupEvent(group, HandlerEvent.BEFORE_CREATE));
|
|
||||||
verify(cache, never()).clear();
|
|
||||||
|
|
||||||
collector.onEvent(new GroupEvent(group, HandlerEvent.CREATE));
|
|
||||||
verify(cache).clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.group.GroupEvent)} with modified groups.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnGroupModificationEvent()
|
|
||||||
{
|
|
||||||
Group group = new Group("xml", "base");
|
|
||||||
Group modifiedGroup = new Group("xml", "base");
|
|
||||||
collector.onEvent(new GroupModificationEvent(modifiedGroup, group, HandlerEvent.BEFORE_MODIFY));
|
|
||||||
verify(cache, never()).clear();
|
|
||||||
|
|
||||||
collector.onEvent(new GroupModificationEvent(modifiedGroup, group, HandlerEvent.MODIFY));
|
|
||||||
verify(cache, never()).clear();
|
|
||||||
|
|
||||||
modifiedGroup.add("test");
|
|
||||||
collector.onEvent(new GroupModificationEvent(modifiedGroup, group, HandlerEvent.MODIFY));
|
|
||||||
verify(cache).clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.repository.RepositoryEvent)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnRepositoryEvent()
|
|
||||||
{
|
|
||||||
Repository repository = RepositoryTestData.createHeartOfGold();
|
|
||||||
collector.onEvent(new RepositoryEvent(repository, HandlerEvent.BEFORE_CREATE));
|
|
||||||
verify(cache, never()).clear();
|
|
||||||
|
|
||||||
collector.onEvent(new RepositoryEvent(repository, HandlerEvent.CREATE));
|
|
||||||
verify(cache).clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.repository.RepositoryEvent)} with modified repository.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnRepositoryModificationEvent()
|
|
||||||
{
|
|
||||||
Repository repositoryModified = RepositoryTestData.createHeartOfGold();
|
|
||||||
repositoryModified.setName("test123");
|
|
||||||
repositoryModified.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test")));
|
|
||||||
|
|
||||||
Repository repository = RepositoryTestData.createHeartOfGold();
|
|
||||||
repository.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test")));
|
|
||||||
|
|
||||||
collector.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.BEFORE_CREATE));
|
|
||||||
verify(cache, never()).clear();
|
|
||||||
|
|
||||||
collector.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
|
||||||
verify(cache, never()).clear();
|
|
||||||
|
|
||||||
repositoryModified.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test")));
|
|
||||||
collector.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
|
||||||
verify(cache, never()).clear();
|
|
||||||
|
|
||||||
repositoryModified.setPermissions(Lists.newArrayList(new sonia.scm.repository.Permission("test123")));
|
|
||||||
collector.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
|
||||||
verify(cache).clear();
|
|
||||||
|
|
||||||
repositoryModified.setPermissions(
|
|
||||||
Lists.newArrayList(new sonia.scm.repository.Permission("test", PermissionType.READ, true))
|
|
||||||
);
|
|
||||||
collector.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
|
||||||
verify(cache, times(2)).clear();
|
|
||||||
|
|
||||||
repositoryModified.setPermissions(
|
|
||||||
Lists.newArrayList(new sonia.scm.repository.Permission("test", PermissionType.WRITE))
|
|
||||||
);
|
|
||||||
collector.onEvent(new RepositoryModificationEvent(repositoryModified, repository, HandlerEvent.CREATE));
|
|
||||||
verify(cache, times(3)).clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.security.StoredAssignedPermissionEvent)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnStoredAssignedPermissionEvent()
|
|
||||||
{
|
|
||||||
StoredAssignedPermission groupPermission = new StoredAssignedPermission(
|
|
||||||
"123", new AssignedPermission("_authenticated", true, "repository:read:*")
|
|
||||||
);
|
|
||||||
collector.onEvent(new StoredAssignedPermissionEvent(HandlerEvent.BEFORE_CREATE, groupPermission));
|
|
||||||
verify(cache, never()).clear();
|
|
||||||
|
|
||||||
collector.onEvent(new StoredAssignedPermissionEvent(HandlerEvent.CREATE, groupPermission));
|
|
||||||
verify(cache).clear();
|
|
||||||
|
|
||||||
|
|
||||||
StoredAssignedPermission userPermission = new StoredAssignedPermission(
|
|
||||||
"123", new AssignedPermission("trillian", false, "repository:read:*")
|
|
||||||
);
|
|
||||||
collector.onEvent(new StoredAssignedPermissionEvent(HandlerEvent.BEFORE_CREATE, userPermission));
|
|
||||||
verify(cache, never()).removeAll(Mockito.any(Filter.class));
|
|
||||||
verify(cache).clear();
|
|
||||||
|
|
||||||
collector.onEvent(new StoredAssignedPermissionEvent(HandlerEvent.CREATE, userPermission));
|
|
||||||
verify(cache).removeAll(Mockito.any(Filter.class));
|
|
||||||
verify(cache).clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link AuthorizationCollector#collect()} without user role.
|
* Tests {@link AuthorizationCollector#collect()} without user role.
|
||||||
*/
|
*/
|
||||||
@@ -402,8 +240,7 @@ public class AuthorizationCollectorTest {
|
|||||||
assertThat(authInfo.getObjectPermissions(), containsInAnyOrder(wp1, wp2));
|
assertThat(authInfo.getObjectPermissions(), containsInAnyOrder(wp1, wp2));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void authenticate(User user, String group, String... groups)
|
private void authenticate(User user, String group, String... groups) {
|
||||||
{
|
|
||||||
SimplePrincipalCollection spc = new SimplePrincipalCollection();
|
SimplePrincipalCollection spc = new SimplePrincipalCollection();
|
||||||
spc.add(user.getName(), "unit");
|
spc.add(user.getName(), "unit");
|
||||||
spc.add(user, "unit");
|
spc.add(user, "unit");
|
||||||
@@ -412,4 +249,16 @@ public class AuthorizationCollectorTest {
|
|||||||
shiro.setSubject(subject);
|
shiro.setSubject(subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link AuthorizationCollector#invalidateCache(sonia.scm.security.AuthorizationChangedEvent)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInvalidateCache() {
|
||||||
|
collector.invalidateCache(AuthorizationChangedEvent.createForEveryUser());
|
||||||
|
verify(cache).clear();
|
||||||
|
|
||||||
|
collector.invalidateCache(AuthorizationChangedEvent.createForUser("dent"));
|
||||||
|
verify(cache).removeAll(Mockito.any(Filter.class));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -54,8 +54,6 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
import sonia.scm.cache.CacheManager;
|
|
||||||
import sonia.scm.cache.MapCacheManager;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
import sonia.scm.group.Group;
|
import sonia.scm.group.Group;
|
||||||
import sonia.scm.group.GroupManager;
|
import sonia.scm.group.GroupManager;
|
||||||
@@ -89,6 +87,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
import sonia.scm.cache.GuavaCacheManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -477,7 +476,7 @@ public class ScmRealmTest
|
|||||||
Collections.EMPTY_LIST
|
Collections.EMPTY_LIST
|
||||||
);
|
);
|
||||||
|
|
||||||
CacheManager cacheManager = new MapCacheManager();
|
GuavaCacheManager cacheManager = new GuavaCacheManager();
|
||||||
|
|
||||||
AdminDetector adminSelector = new AdminDetector(new ScmConfiguration());
|
AdminDetector adminSelector = new AdminDetector(new ScmConfiguration());
|
||||||
LocalDatabaseSynchronizer synchronizer = new LocalDatabaseSynchronizer(
|
LocalDatabaseSynchronizer synchronizer = new LocalDatabaseSynchronizer(
|
||||||
@@ -516,6 +515,7 @@ public class ScmRealmTest
|
|||||||
};
|
};
|
||||||
|
|
||||||
return new ScmRealm(
|
return new ScmRealm(
|
||||||
|
cacheManager,
|
||||||
new AuthenticatorFacade(authManager, requestProvider, responseProvider),
|
new AuthenticatorFacade(authManager, requestProvider, responseProvider),
|
||||||
dummyLoginAttemptHandler,
|
dummyLoginAttemptHandler,
|
||||||
authcCollector,
|
authcCollector,
|
||||||
|
|||||||
Reference in New Issue
Block a user