diff --git a/pom.xml b/pom.xml
index 6c99790d77..6496035d47 100644
--- a/pom.xml
+++ b/pom.xml
@@ -401,6 +401,9 @@
2.3.19
7.6.7.v20120910
+
+ 1.2.1
+
2.1.0.201209190230-r
1.7.5-2
diff --git a/scm-clients/pom.xml b/scm-clients/pom.xml
index a58a221f2e..f8c84d7cac 100644
--- a/scm-clients/pom.xml
+++ b/scm-clients/pom.xml
@@ -23,10 +23,50 @@
+
+
- sonia.scm
scm-core
+ sonia.scm
+ jar
1.21-SNAPSHOT
+
+
+ shiro-core
+ org.apache.shiro
+
+
+ aopalliance
+ aopalliance
+
+
+ guice
+ com.google.inject
+
+
+ guice-multibindings
+ com.google.inject.extensions
+
+
+ guice-servlet
+ com.google.inject.extensions
+
+
+ jersey-core
+ com.sun.jersey
+
+
+ guice-throwingproviders
+ com.google.inject.extensions
+
+
+ commons-lang
+ commons-lang
+
+
diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml
index bf5c6aed48..f46b1256c6 100644
--- a/scm-clients/scm-cli-client/pom.xml
+++ b/scm-clients/scm-cli-client/pom.xml
@@ -32,26 +32,6 @@
provided
-
- scm-core
- sonia.scm
- 1.21-SNAPSHOT
-
-
- guice
- com.google.inject
-
-
- guice-servlet
- com.google.inject.extensions
-
-
- guice-multibindings
- com.google.inject.extensions
-
-
-
-
sonia.scm.clients
scm-client-impl
diff --git a/scm-clients/scm-client-api/pom.xml b/scm-clients/scm-client-api/pom.xml
index 54cb43b037..0ef7e09a76 100644
--- a/scm-clients/scm-client-api/pom.xml
+++ b/scm-clients/scm-client-api/pom.xml
@@ -32,7 +32,7 @@
1.1
provided
-
+
\ No newline at end of file
diff --git a/scm-clients/scm-client-impl/pom.xml b/scm-clients/scm-client-impl/pom.xml
index 11790b70bf..5b5dd2d5b7 100644
--- a/scm-clients/scm-client-impl/pom.xml
+++ b/scm-clients/scm-client-impl/pom.xml
@@ -33,30 +33,6 @@
provided
-
- scm-core
- sonia.scm
- 1.21-SNAPSHOT
-
-
- aopalliance
- aopalliance
-
-
- guice
- com.google.inject
-
-
- guice-multibindings
- com.google.inject.extensions
-
-
- guice-servlet
- com.google.inject.extensions
-
-
-
-
sonia.scm.clients
scm-client-api
diff --git a/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/ClientUtil.java b/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/ClientUtil.java
index 7a19c5d916..e01307fed7 100644
--- a/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/ClientUtil.java
+++ b/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/ClientUtil.java
@@ -66,7 +66,7 @@ public class ClientUtil
* @param response
*/
public static void appendContent(ScmClientException exception,
- ClientResponse response)
+ ClientResponse response)
{
try
{
@@ -86,12 +86,18 @@ public class ClientUtil
* @param expectedStatusCode
*/
public static void checkResponse(ClientResponse response,
- int expectedStatusCode)
+ int expectedStatusCode)
{
int sc = response.getStatus();
if (sc != expectedStatusCode)
{
+ if (logger.isWarnEnabled())
+ {
+ logger.warn("response code {} expected, but {} returned",
+ expectedStatusCode, sc);
+ }
+
sendException(response, sc);
}
}
@@ -109,6 +115,11 @@ public class ClientUtil
if (sc >= 300)
{
+ if (logger.isWarnEnabled())
+ {
+ logger.warn("request failed, response code {} returned", sc);
+ }
+
sendException(response, sc);
}
}
@@ -152,7 +163,7 @@ public class ClientUtil
* @return
*/
public static WebResource createResource(Client client, String url,
- boolean enableLogging)
+ boolean enableLogging)
{
WebResource resource = client.resource(url);
diff --git a/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/JerseyRepositoryClientHandler.java b/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/JerseyRepositoryClientHandler.java
index cc93849fa3..f1c204531b 100644
--- a/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/JerseyRepositoryClientHandler.java
+++ b/scm-clients/scm-client-impl/src/main/java/sonia/scm/client/JerseyRepositoryClientHandler.java
@@ -37,7 +37,6 @@ package sonia.scm.client;
import sonia.scm.NotSupportedFeatuerException;
import sonia.scm.Type;
-import sonia.scm.repository.Changeset;
import sonia.scm.repository.Repository;
import sonia.scm.repository.Tags;
diff --git a/scm-clients/scm-client-impl/src/test/java/sonia/scm/client/it/ClientTestUtil.java b/scm-clients/scm-client-impl/src/test/java/sonia/scm/client/it/ClientTestUtil.java
index b2efca3439..a9caf9d50e 100644
--- a/scm-clients/scm-client-impl/src/test/java/sonia/scm/client/it/ClientTestUtil.java
+++ b/scm-clients/scm-client-impl/src/test/java/sonia/scm/client/it/ClientTestUtil.java
@@ -38,7 +38,6 @@ package sonia.scm.client.it;
import sonia.scm.client.ClientUtil;
import sonia.scm.client.JerseyClientProvider;
import sonia.scm.client.JerseyClientSession;
-import sonia.scm.client.ScmUrlProvider;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.url.UrlProvider;
@@ -106,7 +105,7 @@ public class ClientTestUtil
*
*/
public static JerseyClientSession createSession(String username,
- String password)
+ String password)
{
JerseyClientProvider provider = new JerseyClientProvider(REQUEST_LOGGING);
diff --git a/scm-core/pom.xml b/scm-core/pom.xml
index 5147be4351..badb2baa00 100644
--- a/scm-core/pom.xml
+++ b/scm-core/pom.xml
@@ -33,6 +33,14 @@
${slf4j.version}
+
+
+
+ org.apache.shiro
+ shiro-core
+ ${shiro.version}
+
+
diff --git a/scm-core/src/main/java/sonia/scm/HandlerEvent.java b/scm-core/src/main/java/sonia/scm/HandlerEvent.java
index 0bedf4be5b..a15522be33 100644
--- a/scm-core/src/main/java/sonia/scm/HandlerEvent.java
+++ b/scm-core/src/main/java/sonia/scm/HandlerEvent.java
@@ -44,33 +44,75 @@ public enum HandlerEvent
/**
* After a new object is stored by a handler.
*/
- CREATE,
+ CREATE(true),
/**
* After a object is modified by a handler.
*/
- MODIFY,
+ MODIFY(true),
/**
* After a object is removed by a handler.
*/
- DELETE,
+ DELETE(true),
/**
* Before a new object is stored by a handler.
* @since 1.16
*/
- BEFORE_CREATE,
+ BEFORE_CREATE(false),
/**
* Before a object is modified by a handler.
* @since 1.16
*/
- BEFORE_MODIFY,
+ BEFORE_MODIFY(false),
/**
* Before a object is removed by a handler.
* @since 1.16
*/
- BEFORE_DELETE
+ BEFORE_DELETE(false);
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param post
+ */
+ private HandlerEvent(boolean post)
+ {
+ this.post = post;
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Returns true if the event is fired after the action is occurred.
+ *
+ *
+ * @return true if the event is fired after the action is occurred
+ * @since 1.21
+ */
+ public boolean isPost()
+ {
+ return post;
+ }
+
+ /**
+ * Returns true if the event is fired before the action is occurred.
+ *
+ *
+ * @return true if the event is fired before the action is occurred
+ * @since 1.21
+ */
+ public boolean isPre()
+ {
+ return !post;
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private boolean post;
}
diff --git a/scm-core/src/main/java/sonia/scm/SCMContext.java b/scm-core/src/main/java/sonia/scm/SCMContext.java
index b376646de0..be14775fc3 100644
--- a/scm-core/src/main/java/sonia/scm/SCMContext.java
+++ b/scm-core/src/main/java/sonia/scm/SCMContext.java
@@ -35,6 +35,7 @@ package sonia.scm;
//~--- non-JDK imports --------------------------------------------------------
+import sonia.scm.user.User;
import sonia.scm.util.ServiceUtil;
/**
@@ -52,6 +53,14 @@ public class SCMContext
/** Name of the anonymous user */
public static final String USER_ANONYMOUS = "anonymous";
+ /**
+ * the anonymous user
+ * @since 1.21
+ */
+ public static final User ANONYMOUS = new User(USER_ANONYMOUS,
+ "SCM Anonymous",
+ "scm-anonymous@scm-manager.com");
+
/** Singleton instance of {@link SCMContextProvider} */
private static volatile SCMContextProvider provider;
diff --git a/scm-core/src/main/java/sonia/scm/ScmState.java b/scm-core/src/main/java/sonia/scm/ScmState.java
index 3de189d7cf..8508d90c67 100644
--- a/scm-core/src/main/java/sonia/scm/ScmState.java
+++ b/scm-core/src/main/java/sonia/scm/ScmState.java
@@ -73,10 +73,10 @@ public class ScmState
* @param repositoryTypes - available repository types
* @param clientConfig - client configuration
*/
+ @Deprecated
public ScmState(SCMContextProvider provider,
- WebSecurityContext securityContext,
- Collection repositoryTypes,
- ScmClientConfig clientConfig)
+ WebSecurityContext securityContext, Collection repositoryTypes,
+ ScmClientConfig clientConfig)
{
this(provider, securityContext, repositoryTypes, null, clientConfig);
}
@@ -93,10 +93,10 @@ public class ScmState
*
* @since 1.14
*/
+ @Deprecated
public ScmState(SCMContextProvider provider,
- WebSecurityContext securityContext,
- Collection repositoryTypes, String defaultUserType,
- ScmClientConfig clientConfig)
+ WebSecurityContext securityContext, Collection repositoryTypes,
+ String defaultUserType, ScmClientConfig clientConfig)
{
this.version = provider.getVersion();
this.user = securityContext.getUser();
@@ -106,6 +106,31 @@ public class ScmState
this.defaultUserType = defaultUserType;
}
+ /**
+ * Constructs {@link ScmState} object.
+ *
+ *
+ * @param provider context provider
+ * @param user current user
+ * @param groups groups of the current user
+ * @param repositoryTypes available repository types
+ * @param defaultUserType default user type
+ * @param clientConfig client configuration
+ *
+ * @since 1.21
+ */
+ public ScmState(SCMContextProvider provider, User user,
+ Collection groups, Collection repositoryTypes,
+ String defaultUserType, ScmClientConfig clientConfig)
+ {
+ this.version = provider.getVersion();
+ this.user = user;
+ this.groups = groups;
+ this.repositoryTypes = repositoryTypes;
+ this.clientConfig = clientConfig;
+ this.defaultUserType = defaultUserType;
+ }
+
//~--- get methods ----------------------------------------------------------
/**
diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/AdministrationSecurityContext.java b/scm-core/src/main/java/sonia/scm/group/GroupNames.java
similarity index 67%
rename from scm-webapp/src/main/java/sonia/scm/web/security/AdministrationSecurityContext.java
rename to scm-core/src/main/java/sonia/scm/group/GroupNames.java
index a77142d3af..867e575e64 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/security/AdministrationSecurityContext.java
+++ b/scm-core/src/main/java/sonia/scm/group/GroupNames.java
@@ -30,38 +30,64 @@
*/
-
-package sonia.scm.web.security;
+package sonia.scm.group;
//~--- non-JDK imports --------------------------------------------------------
-import sonia.scm.user.User;
+import com.google.common.collect.Lists;
//~--- JDK imports ------------------------------------------------------------
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
+import java.io.Serializable;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
/**
+ * This class represents all associated groups for a user.
*
* @author Sebastian Sdorra
+ * @since 1.21
*/
-public class AdministrationSecurityContext implements WebSecurityContext
+public final class GroupNames implements Serializable, Iterable
{
+ /** Field description */
+ private static final long serialVersionUID = 8615685985213897947L;
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ */
+ public GroupNames()
+ {
+ this.collection = Collections.EMPTY_LIST;
+ }
+
/**
* Constructs ...
*
*
- * @param user
+ * @param collection
*/
- public AdministrationSecurityContext(User user)
+ public GroupNames(Collection collection)
{
- this.user = user;
+ this.collection = Collections.unmodifiableCollection(collection);
+ }
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param groupName
+ * @param groupNames
+ */
+ public GroupNames(String groupName, String... groupNames)
+ {
+ this.collection = Lists.asList(groupName, groupNames);
}
//~--- methods --------------------------------------------------------------
@@ -70,32 +96,25 @@ public class AdministrationSecurityContext implements WebSecurityContext
* Method description
*
*
- * @param request
- * @param response
- * @param username
- * @param password
+ * @param groupName
*
* @return
*/
- @Override
- public User authenticate(HttpServletRequest request,
- HttpServletResponse response, String username,
- String password)
+ public boolean contains(String groupName)
{
- throw new UnsupportedOperationException("Not supported yet.");
+ return collection.contains(groupName);
}
/**
* Method description
*
*
- * @param request
- * @param response
+ * @return
*/
@Override
- public void logout(HttpServletRequest request, HttpServletResponse response)
+ public Iterator iterator()
{
- throw new UnsupportedOperationException("Not supported yet.");
+ return collection.iterator();
}
//~--- get methods ----------------------------------------------------------
@@ -106,41 +125,13 @@ public class AdministrationSecurityContext implements WebSecurityContext
*
* @return
*/
- @Override
- public Collection getGroups()
+ public Collection getCollection()
{
- return groups;
- }
-
- /**
- * Method description
- *
- *
- * @return
- */
- @Override
- public User getUser()
- {
- return user;
- }
-
- /**
- * Method description
- *
- *
- * @return
- */
- @Override
- public boolean isAuthenticated()
- {
- return true;
+ return collection;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
- private List groups = new ArrayList();
-
- /** Field description */
- private User user;
+ private Collection collection;
}
diff --git a/scm-core/src/main/java/sonia/scm/repository/PermissionUtil.java b/scm-core/src/main/java/sonia/scm/repository/PermissionUtil.java
index dc6a48b118..6d77ed8617 100644
--- a/scm-core/src/main/java/sonia/scm/repository/PermissionUtil.java
+++ b/scm-core/src/main/java/sonia/scm/repository/PermissionUtil.java
@@ -37,18 +37,21 @@ package sonia.scm.repository;
import com.google.inject.Provider;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.config.ScmConfiguration;
+import sonia.scm.group.GroupNames;
+import sonia.scm.security.Role;
import sonia.scm.security.ScmSecurityException;
-import sonia.scm.user.User;
import sonia.scm.util.AssertUtil;
import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
-import java.util.Collection;
import java.util.List;
/**
@@ -73,14 +76,13 @@ public class PermissionUtil
* @param repository
* @param securityContext
* @param pt
+ * @deprecated
*/
+ @Deprecated
public static void assertPermission(Repository repository,
- WebSecurityContext securityContext, PermissionType pt)
+ WebSecurityContext securityContext, PermissionType pt)
{
- if (!hasPermission(repository, securityContext, pt))
- {
- throw new ScmSecurityException("action denied");
- }
+ assertPermission(repository, pt);
}
/**
@@ -91,13 +93,32 @@ public class PermissionUtil
* @param securityContextProvider
* @param pt
*/
+ @Deprecated
public static void assertPermission(Repository repository,
- Provider securityContextProvider,
- PermissionType pt)
+ Provider securityContextProvider, PermissionType pt)
{
assertPermission(repository, securityContextProvider.get(), pt);
}
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ * @param securityContextProvider
+ * @param pt
+ *
+ * @since 1.21
+ */
+ @Deprecated
+ public static void assertPermission(Repository repository, PermissionType pt)
+ {
+ if (!hasPermission(null, repository, pt))
+ {
+ throw new ScmSecurityException("action denied");
+ }
+ }
+
//~--- get methods ----------------------------------------------------------
/**
@@ -109,12 +130,13 @@ public class PermissionUtil
* @param pt
*
* @return
+ * @deprecated
*/
+ @Deprecated
public static boolean hasPermission(Repository repository,
- Provider securityContextProvider,
- PermissionType pt)
+ Provider securityContextProvider, PermissionType pt)
{
- return hasPermission(repository, securityContextProvider.get(), pt);
+ return hasPermission(null, repository, pt);
}
/**
@@ -126,39 +148,67 @@ public class PermissionUtil
* @param pt
*
* @return
+ * @deprecated use {@link #hasPermission(Repository,PermissionType)} instead
*/
+ @Deprecated
public static boolean hasPermission(Repository repository,
- WebSecurityContext securityContext, PermissionType pt)
+ WebSecurityContext securityContext, PermissionType pt)
+ {
+ return hasPermission(null, repository, pt);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param configuration
+ * @param repository
+ * @param pt
+ *
+ * @return
+ *
+ * @since 1.21
+ */
+ public static boolean hasPermission(ScmConfiguration configuration,
+ Repository repository, PermissionType pt)
{
boolean result = false;
- if (securityContext != null)
+ Subject subject = SecurityUtils.getSubject();
+
+ if (subject.isAuthenticated())
{
- User user = securityContext.getUser();
+ String username = subject.getPrincipal().toString();
- if (user != null)
+ AssertUtil.assertIsNotEmpty(username);
+
+ if (subject.hasRole(Role.ADMIN)
+ || ((pt == PermissionType.READ) && repository.isPublicReadable()))
{
- String username = user.getName();
+ result = true;
+ }
+ else
+ {
+ List permissions = repository.getPermissions();
- AssertUtil.assertIsNotEmpty(username);
-
- if (user.isAdmin()
- || ((pt == PermissionType.READ) && repository.isPublicReadable()))
+ if (permissions != null)
{
- result = true;
- }
- else
- {
- List permissions = repository.getPermissions();
+ GroupNames groupNames =
+ subject.getPrincipals().oneByType(GroupNames.class);
+
+ result = hasPermission(permissions, username, groupNames, pt);
- if (permissions != null)
- {
- result = hasPermission(permissions, username,
- securityContext.getGroups(), pt);
- }
}
}
}
+ else
+ {
+
+ // check anonymous access
+ result = (configuration != null)
+ && configuration.isAnonymousAccessEnabled()
+ && repository.isPublicReadable() && (pt == PermissionType.READ);
+ }
return result;
}
@@ -173,10 +223,28 @@ public class PermissionUtil
*
* @return true if the repository is writable
* @since 1.14
+ * @deprecated use {@link #isWritable(ScmConfiguration, Repository)} instead
+ */
+ @Deprecated
+ public static boolean isWritable(ScmConfiguration configuration,
+ Repository repository, WebSecurityContext securityContext)
+ {
+ return isWritable(configuration, repository);
+ }
+
+ /**
+ * Returns true if the repository is writable.
+ *
+ *
+ * @param configuration SCM-Manager main configuration
+ * @param repository repository to check
+ * @param securityContext current user security context
+ *
+ * @return true if the repository is writable
+ * @since 1.21
*/
public static boolean isWritable(ScmConfiguration configuration,
- Repository repository,
- WebSecurityContext securityContext)
+ Repository repository)
{
boolean permitted = false;
@@ -185,13 +253,13 @@ public class PermissionUtil
if (logger.isWarnEnabled())
{
logger.warn("{} is archived and is not writeable",
- repository.getName());
+ repository.getName());
}
}
else
{
- permitted = PermissionUtil.hasPermission(repository, securityContext,
- PermissionType.WRITE);
+ permitted = PermissionUtil.hasPermission(configuration, repository,
+ PermissionType.WRITE);
}
return permitted;
@@ -209,7 +277,7 @@ public class PermissionUtil
* @return
*/
private static boolean hasPermission(List permissions,
- String username, Collection groups, PermissionType pt)
+ String username, GroupNames groups, PermissionType pt)
{
boolean result = false;
@@ -218,8 +286,8 @@ public class PermissionUtil
String name = p.getName();
if (((name != null) && (p.getType().getValue() >= pt.getValue()))
- && (name.equals(username)
- || (p.isGroupPermission() && groups.contains(p.getName()))))
+ && (name.equals(username)
+ || (p.isGroupPermission() && groups.contains(p.getName()))))
{
result = true;
diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java
index 23825d0ee5..eb1371ddd7 100644
--- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java
+++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java
@@ -38,7 +38,6 @@ package sonia.scm.repository.api;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.slf4j.Logger;
@@ -47,6 +46,7 @@ import org.slf4j.LoggerFactory;
import sonia.scm.HandlerEvent;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
+import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.BlameResult;
import sonia.scm.repository.Branches;
import sonia.scm.repository.BrowserResult;
@@ -65,7 +65,6 @@ import sonia.scm.repository.Tags;
import sonia.scm.repository.spi.RepositoryServiceProvider;
import sonia.scm.repository.spi.RepositoryServiceResolver;
import sonia.scm.security.ScmSecurityException;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -134,16 +133,40 @@ public final class RepositoryServiceFactory
* @param securityContextProvider provider for the current security context
* @param resolvers a set of {@link RepositoryServiceResolver}
* @param preProcessorUtil helper object for pre processor handling
+ *
+ * @deprecated
*/
- @Inject
+ @Deprecated
public RepositoryServiceFactory(CacheManager cacheManager,
RepositoryManager repositoryManager,
- Provider securityContextProvider,
Set resolvers, PreProcessorUtil preProcessorUtil)
{
+ this(null, cacheManager, repositoryManager, resolvers, preProcessorUtil);
+ }
+
+ /**
+ * Constructs a new {@link RepositoryServiceFactory}. This constructor
+ * should not be called manually, it should only be used by the injection
+ * container.
+ *
+ *
+ * @param configuration configuration
+ * @param cacheManager cache manager
+ * @param repositoryManager manager for repositories
+ * @param securityContextProvider provider for the current security context
+ * @param resolvers a set of {@link RepositoryServiceResolver}
+ * @param preProcessorUtil helper object for pre processor handling
+ *
+ * @since 1.21
+ */
+ @Inject
+ public RepositoryServiceFactory(ScmConfiguration configuration,
+ CacheManager cacheManager, RepositoryManager repositoryManager,
+ Set resolvers, PreProcessorUtil preProcessorUtil)
+ {
+ this.configuration = configuration;
this.cacheManager = cacheManager;
this.repositoryManager = repositoryManager;
- this.securityContextProvider = securityContextProvider;
this.resolvers = resolvers;
this.preProcessorUtil = preProcessorUtil;
@@ -250,8 +273,11 @@ public final class RepositoryServiceFactory
Preconditions.checkNotNull(repository, "repository is required");
// check for read permissions of current user
- PermissionUtil.assertPermission(repository, securityContextProvider,
- PermissionType.READ);
+ if (!PermissionUtil.hasPermission(configuration, repository,
+ PermissionType.READ))
+ {
+ throw new ScmSecurityException("read permission are required");
+ }
RepositoryService service = null;
@@ -404,6 +430,9 @@ public final class RepositoryServiceFactory
/** Field description */
private CacheManager cacheManager;
+ /** scm-manager configuration */
+ private ScmConfiguration configuration;
+
/** Field description */
private PreProcessorUtil preProcessorUtil;
@@ -412,7 +441,4 @@ public final class RepositoryServiceFactory
/** Field description */
private Set resolvers;
-
- /** Field description */
- private Provider securityContextProvider;
}
diff --git a/scm-core/src/main/java/sonia/scm/security/RepositoryPermission.java b/scm-core/src/main/java/sonia/scm/security/RepositoryPermission.java
new file mode 100644
index 0000000000..b1ffcde938
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/security/RepositoryPermission.java
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2010, 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.common.base.Objects;
+
+import org.apache.shiro.authz.Permission;
+
+import sonia.scm.repository.PermissionType;
+import sonia.scm.repository.Repository;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.Serializable;
+
+/**
+ * This class represents the permission to a repository of a user.
+ *
+ * @author Sebastian Sdorra
+ * @since 1.21
+ */
+public final class RepositoryPermission implements Permission, Serializable
+{
+
+ /** Field description */
+ public static final String WILDCARD = "*";
+
+ /** Field description */
+ private static final long serialVersionUID = 3832804235417228043L;
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param repository
+ * @param permissionType
+ */
+ public RepositoryPermission(Repository repository,
+ PermissionType permissionType)
+ {
+ this(repository.getId(), permissionType);
+ }
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param repositoryId
+ * @param permissionType
+ */
+ public RepositoryPermission(String repositoryId,
+ PermissionType permissionType)
+ {
+ this.repositoryId = repositoryId;
+ this.permissionType = permissionType;
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param obj
+ *
+ * @return
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+
+ final RepositoryPermission other = (RepositoryPermission) obj;
+
+ return Objects.equal(repositoryId, other.repositoryId)
+ && Objects.equal(permissionType, other.permissionType);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public int hashCode()
+ {
+ return Objects.hashCode(repositoryId, permissionType);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param p
+ *
+ * @return
+ */
+ @Override
+ public boolean implies(Permission p)
+ {
+ boolean result = false;
+
+ if (p instanceof RepositoryPermission)
+ {
+ RepositoryPermission rp = (RepositoryPermission) p;
+
+ //J-
+ result = (repositoryId.equals(WILDCARD) || repositoryId.equals(rp.repositoryId))
+ && (permissionType.getValue() >= rp.permissionType.getValue());
+ //J+
+ }
+
+ return result;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public String toString()
+ {
+ //J-
+ return Objects.toStringHelper(this)
+ .add("repositoryId", repositoryId)
+ .add("permissionType", permissionType)
+ .toString();
+ //J+
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public PermissionType getPermissionType()
+ {
+ return permissionType;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getRepositoryId()
+ {
+ return repositoryId;
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private PermissionType permissionType;
+
+ /** Field description */
+ private String repositoryId;
+}
diff --git a/scm-core/src/main/java/sonia/scm/security/Role.java b/scm-core/src/main/java/sonia/scm/security/Role.java
new file mode 100644
index 0000000000..b82901df34
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/security/Role.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2010, 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;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ * @since 1.21
+ */
+public final class Role
+{
+
+ /** Field description */
+ public static final String ADMIN = "admin";
+
+ /** Field description */
+ public static final String USER = "user";
+}
diff --git a/scm-core/src/main/java/sonia/scm/security/SecurityContext.java b/scm-core/src/main/java/sonia/scm/security/SecurityContext.java
index 226a247d4a..34baca2f5e 100644
--- a/scm-core/src/main/java/sonia/scm/security/SecurityContext.java
+++ b/scm-core/src/main/java/sonia/scm/security/SecurityContext.java
@@ -40,7 +40,9 @@ import sonia.scm.user.User;
/**
*
* @author Sebastian Sdorra
+ * @deprecated use {@link SecurityUtils#getSecurityManager()} instead.
*/
+@Deprecated
public interface SecurityContext
{
diff --git a/scm-core/src/main/java/sonia/scm/security/Tokens.java b/scm-core/src/main/java/sonia/scm/security/Tokens.java
new file mode 100644
index 0000000000..d9f668fa12
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/security/Tokens.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2010, 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.subject.Subject;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Create tokens for security reasons.
+ *
+ * @author Sebastian Sdorra
+ * @since 1.21
+ */
+public final class Tokens
+{
+
+ /**
+ * Build an {@link AuthenticationToken} for use with
+ * {@link Subject#login(org.apache.shiro.authc.AuthenticationToken)}.
+ *
+ *
+ * @param request servlet request
+ * @param username username of the user to authenticate
+ * @param password password of the user to authenticate
+ *
+ * @return
+ */
+ public static AuthenticationToken createAuthenticationToken(
+ HttpServletRequest request, String username, String password)
+ {
+ return new UsernamePasswordToken(username, password,
+ request.getRemoteAddr());
+ }
+}
diff --git a/scm-core/src/main/java/sonia/scm/template/TemplateParseException.java b/scm-core/src/main/java/sonia/scm/template/TemplateParseException.java
index f374b43b27..2de045aeef 100644
--- a/scm-core/src/main/java/sonia/scm/template/TemplateParseException.java
+++ b/scm-core/src/main/java/sonia/scm/template/TemplateParseException.java
@@ -1,34 +1,35 @@
/**
- * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ * Copyright (c) 2010, 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 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.
+ * 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.template;
//~--- JDK imports ------------------------------------------------------------
diff --git a/scm-core/src/main/java/sonia/scm/util/SecurityUtil.java b/scm-core/src/main/java/sonia/scm/util/SecurityUtil.java
index 1bf585ddf9..d8bf4c40d7 100644
--- a/scm-core/src/main/java/sonia/scm/util/SecurityUtil.java
+++ b/scm-core/src/main/java/sonia/scm/util/SecurityUtil.java
@@ -37,7 +37,11 @@ package sonia.scm.util;
import com.google.inject.Provider;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
import sonia.scm.SCMContext;
+import sonia.scm.security.Role;
import sonia.scm.security.ScmSecurityException;
import sonia.scm.security.SecurityContext;
import sonia.scm.user.User;
@@ -54,36 +58,51 @@ public class SecurityUtil
*
*
* @param contextProvider
+ * @deprecated use {@link Subject#checkRole(java.lang.String)} with {
+ * @link Role#ADMIN} instead.
*/
+ @Deprecated
public static void assertIsAdmin(
- Provider extends SecurityContext> contextProvider)
+ Provider extends SecurityContext> contextProvider)
{
- assertIsAdmin(contextProvider.get());
+ assertIsAdmin();
}
/**
- * Method description
+ * This method is only present for compatibility reasons.
+ * Use {@link Subject#checkRole(java.lang.String)} with {
+ * @link Role#ADMIN} instead.
*
- *
- * @param context
+ * @since 1.21
*/
- public static void assertIsAdmin(SecurityContext context)
+ public static void assertIsAdmin()
{
- AssertUtil.assertIsNotNull(context);
+ Subject subject = SecurityUtils.getSubject();
- User user = context.getUser();
-
- if (user == null)
+ if (!subject.isAuthenticated())
{
throw new ScmSecurityException("user is not authenticated");
}
-
- if (!user.isAdmin())
+ else if (!subject.hasRole(Role.ADMIN))
{
throw new ScmSecurityException("admin account is required");
}
}
+ /**
+ * Method description
+ *
+ *
+ * @param context
+ * @deprecated use {@link Subject#checkRole(java.lang.String)} with {
+ * @link Role#ADMIN} instead.
+ */
+ @Deprecated
+ public static void assertIsAdmin(SecurityContext context)
+ {
+ assertIsAdmin();
+ }
+
/**
* Method description
*
@@ -91,7 +110,7 @@ public class SecurityUtil
* @param contextProvider
*/
public static void assertIsNotAnonymous(
- Provider extends SecurityContext> contextProvider)
+ Provider extends SecurityContext> contextProvider)
{
if (isAnonymous(contextProvider))
{
@@ -124,7 +143,7 @@ public class SecurityUtil
* @return
*/
public static User getCurrentUser(
- Provider extends SecurityContext> contextProvider)
+ Provider extends SecurityContext> contextProvider)
{
AssertUtil.assertIsNotNull(contextProvider);
@@ -151,7 +170,7 @@ public class SecurityUtil
* @return
*/
public static boolean isAdmin(
- Provider extends SecurityContext> contextProvider)
+ Provider extends SecurityContext> contextProvider)
{
return isAdmin(contextProvider.get());
}
@@ -169,7 +188,7 @@ public class SecurityUtil
AssertUtil.assertIsNotNull(contextProvider);
return (contextProvider.getUser() != null)
- && contextProvider.getUser().isAdmin();
+ && contextProvider.getUser().isAdmin();
}
/**
@@ -181,7 +200,7 @@ public class SecurityUtil
* @return
*/
public static boolean isAnonymous(
- Provider extends SecurityContext> contextProvider)
+ Provider extends SecurityContext> contextProvider)
{
return isAnonymous(contextProvider.get());
}
diff --git a/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java
index af72d763e4..fc2cc6d681 100644
--- a/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java
+++ b/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java
@@ -39,11 +39,17 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.subject.Subject;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import sonia.scm.SCMContext;
+import sonia.scm.config.ScmConfiguration;
import sonia.scm.user.User;
-import sonia.scm.util.AssertUtil;
import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
import sonia.scm.web.security.WebSecurityContext;
@@ -87,12 +93,23 @@ public class BasicAuthenticationFilter extends HttpFilter
*
*
* @param securityContextProvider
+ * @deprecated use the constructor with out arguments instead.
+ */
+ @Deprecated
+ public BasicAuthenticationFilter(
+ Provider securityContextProvider) {}
+
+ /**
+ * Constructs a new basic authenticaton filter
+ *
+ * @param configuration scm-manager global configuration
+ *
+ * @since 1.21
*/
@Inject
- public BasicAuthenticationFilter(
- Provider securityContextProvider)
+ public BasicAuthenticationFilter(ScmConfiguration configuration)
{
- this.securityContextProvider = securityContextProvider;
+ this.configuration = configuration;
}
//~--- methods --------------------------------------------------------------
@@ -110,12 +127,10 @@ public class BasicAuthenticationFilter extends HttpFilter
*/
@Override
protected void doFilter(HttpServletRequest request,
- HttpServletResponse response, FilterChain chain)
- throws IOException, ServletException
+ HttpServletResponse response, FilterChain chain)
+ throws IOException, ServletException
{
- WebSecurityContext securityContext = securityContextProvider.get();
-
- AssertUtil.assertIsNotNull(securityContext);
+ Subject subject = SecurityUtils.getSubject();
User user = null;
String authentication = request.getHeader(HEADER_AUTHORIZATION);
@@ -127,7 +142,7 @@ public class BasicAuthenticationFilter extends HttpFilter
logger.trace("found basic authorization header, start authentication");
}
- user = authenticate(request, response, securityContext, authentication);
+ user = authenticate(request, response, subject, authentication);
if (logger.isTraceEnabled())
{
@@ -141,14 +156,20 @@ public class BasicAuthenticationFilter extends HttpFilter
}
}
}
- else if (securityContext.isAuthenticated())
+ else if (subject.isAuthenticated())
{
if (logger.isTraceEnabled())
{
logger.trace("user is allready authenticated");
}
- user = securityContext.getUser();
+ user = subject.getPrincipals().oneByType(User.class);
+ }
+ else if ((configuration != null)
+ && configuration.isAnonymousAccessEnabled())
+ {
+ user = SCMContext.ANONYMOUS;
+
}
if (user == null)
@@ -158,12 +179,12 @@ public class BasicAuthenticationFilter extends HttpFilter
logger.trace("could not find user send unauthorized");
}
- HttpUtil.sendUnauthorized(request, response);
+ handleUnauthorized(request, response, chain);
}
else
{
chain.doFilter(new SecurityHttpServletRequestWrapper(request, user),
- response);
+ response);
}
}
@@ -181,9 +202,8 @@ public class BasicAuthenticationFilter extends HttpFilter
* @since 1.8
*/
protected void handleUnauthorized(HttpServletRequest request,
- HttpServletResponse response,
- FilterChain chain)
- throws IOException, ServletException
+ HttpServletResponse response, FilterChain chain)
+ throws IOException, ServletException
{
HttpUtil.sendUnauthorized(request, response);
}
@@ -195,14 +215,13 @@ public class BasicAuthenticationFilter extends HttpFilter
* @param request
* @param response
* @param securityContext
+ * @param subject
* @param authentication
*
* @return
*/
private User authenticate(HttpServletRequest request,
- HttpServletResponse response,
- WebSecurityContext securityContext,
- String authentication)
+ HttpServletResponse response, Subject subject, String authentication)
{
String token = authentication.substring(6);
@@ -223,8 +242,25 @@ public class BasicAuthenticationFilter extends HttpFilter
logger.trace("try to authenticate user {}", username);
}
- user = securityContext.authenticate(request, response, username,
- password);
+ try
+ {
+
+ subject.login(new UsernamePasswordToken(username, password,
+ request.getRemoteAddr()));
+ user = subject.getPrincipals().oneByType(User.class);
+ }
+ catch (AuthenticationException ex)
+ {
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("authentication failed for user ".concat(username),
+ ex);
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("authentication failed for user {}", username);
+ }
+ }
}
else if (logger.isWarnEnabled())
{
@@ -242,5 +278,5 @@ public class BasicAuthenticationFilter extends HttpFilter
//~--- fields ---------------------------------------------------------------
/** Field description */
- private Provider securityContextProvider;
+ private ScmConfiguration configuration;
}
diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java
index fd03813a46..1d419d3cdb 100644
--- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java
+++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java
@@ -38,18 +38,18 @@ package sonia.scm.web.filter;
import com.google.common.base.Splitter;
import com.google.inject.Provider;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ArgumentIsInvalidException;
-import sonia.scm.SCMContext;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.PermissionType;
import sonia.scm.repository.PermissionUtil;
import sonia.scm.repository.Repository;
import sonia.scm.security.ScmSecurityException;
-import sonia.scm.user.User;
-import sonia.scm.util.AssertUtil;
import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
import sonia.scm.web.security.WebSecurityContext;
@@ -78,6 +78,18 @@ public abstract class PermissionFilter extends HttpFilter
//~--- constructors ---------------------------------------------------------
+ /**
+ * Constructs a new permission filter
+ *
+ * @param configuration global scm-manager configuration
+ *
+ * @since 1.21
+ */
+ public PermissionFilter(ScmConfiguration configuration)
+ {
+ this.configuration = configuration;
+ }
+
/**
* Constructs ...
*
@@ -85,12 +97,13 @@ public abstract class PermissionFilter extends HttpFilter
*
* @param configuration
* @param securityContextProvider
+ * @deprecated
*/
+ @Deprecated
public PermissionFilter(ScmConfiguration configuration,
- Provider securityContextProvider)
+ Provider securityContextProvider)
{
this.configuration = configuration;
- this.securityContextProvider = securityContextProvider;
}
//~--- get methods ----------------------------------------------------------
@@ -130,97 +143,81 @@ public abstract class PermissionFilter extends HttpFilter
*/
@Override
protected void doFilter(HttpServletRequest request,
- HttpServletResponse response, FilterChain chain)
- throws IOException, ServletException
+ HttpServletResponse response, FilterChain chain)
+ throws IOException, ServletException
{
- WebSecurityContext securityContext = securityContextProvider.get();
+ Subject subject = SecurityUtils.getSubject();
- AssertUtil.assertIsNotNull(securityContext);
-
- User user = securityContext.getUser();
-
- if (user != null)
+ try
{
- try
+ Repository repository = getRepository(request);
+
+ if (repository != null)
{
- Repository repository = getRepository(request);
+ boolean writeRequest = isWriteRequest(request);
- if (repository != null)
+ if (hasPermission(repository, writeRequest))
{
- boolean writeRequest = isWriteRequest(request);
-
- if (hasPermission(repository, securityContext, writeRequest))
+ if (logger.isTraceEnabled())
{
- if (logger.isTraceEnabled())
- {
- logger.trace("{} access to repository {} for user {} granted",
- new Object[] { writeRequest
- ? "write"
- : "read", repository.getName(),
- user.getName() });
- }
-
- chain.doFilter(request, response);
+ logger.trace("{} access to repository {} for user {} granted",
+ new Object[] { writeRequest
+ ? "write"
+ : "read", repository.getName(), subject.getPrincipal() });
}
- else
- {
- if (logger.isInfoEnabled())
- {
- logger.info("{} access to repository {} for user {} denied",
- new Object[] { writeRequest
- ? "write"
- : "read", repository.getName(),
- user.getName() });
- }
- sendAccessDenied(response, user);
- }
+ chain.doFilter(request, response);
}
else
{
- if (logger.isDebugEnabled())
+ if (logger.isInfoEnabled())
{
- logger.debug("repository not found");
+ logger.info("{} access to repository {} for user {} denied",
+ new Object[] { writeRequest
+ ? "write"
+ : "read", repository.getName(), subject.getPrincipal() });
}
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ sendAccessDenied(response, subject);
}
}
- catch (ArgumentIsInvalidException ex)
+ else
{
- if (logger.isTraceEnabled())
+ if (logger.isDebugEnabled())
{
- logger.trace(
- "wrong request at ".concat(request.getRequestURI()).concat(
- " send redirect"), ex);
- }
- else if (logger.isWarnEnabled())
- {
- logger.warn("wrong request at {} send redirect",
- request.getRequestURI());
+ logger.debug("repository not found");
}
- response.sendRedirect(getRepositoryRootHelpUrl(request));
- }
- catch (ScmSecurityException ex)
- {
- if (logger.isWarnEnabled())
- {
- logger.warn("user {} has not enough permissions", user.getName());
- }
-
- sendAccessDenied(response, user);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
- else
+ catch (ArgumentIsInvalidException ex)
{
- if (logger.isDebugEnabled())
+ if (logger.isTraceEnabled())
{
- logger.debug("user in not authenticated");
+ logger.trace(
+ "wrong request at ".concat(request.getRequestURI()).concat(
+ " send redirect"), ex);
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("wrong request at {} send redirect",
+ request.getRequestURI());
}
- response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ response.sendRedirect(getRepositoryRootHelpUrl(request));
}
+ catch (ScmSecurityException ex)
+ {
+ if (logger.isWarnEnabled())
+ {
+ logger.warn("user {} has not enough permissions",
+ subject.getPrincipal());
+ }
+
+ sendAccessDenied(response, subject);
+ }
+
}
/**
@@ -234,8 +231,8 @@ public abstract class PermissionFilter extends HttpFilter
private String extractType(HttpServletRequest request)
{
Iterator it = Splitter.on(
- HttpUtil.SEPARATOR_PATH).omitEmptyStrings().split(
- request.getRequestURI()).iterator();
+ HttpUtil.SEPARATOR_PATH).omitEmptyStrings().split(
+ request.getRequestURI()).iterator();
String type = it.next();
if (Util.isNotEmpty(request.getContextPath()))
@@ -252,19 +249,20 @@ public abstract class PermissionFilter extends HttpFilter
*
* @param response
* @param user
+ * @param subject
*
* @throws IOException
*/
- private void sendAccessDenied(HttpServletResponse response, User user)
- throws IOException
+ private void sendAccessDenied(HttpServletResponse response, Subject subject)
+ throws IOException
{
- if (SCMContext.USER_ANONYMOUS.equals(user.getName()))
+ if (subject.isAuthenticated())
{
- HttpUtil.sendUnauthorized(response);
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
else
{
- response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ HttpUtil.sendUnauthorized(response);
}
}
@@ -299,21 +297,18 @@ public abstract class PermissionFilter extends HttpFilter
*
* @return
*/
- private boolean hasPermission(Repository repository,
- WebSecurityContext securityContext,
- boolean writeRequest)
+ private boolean hasPermission(Repository repository, boolean writeRequest)
{
boolean permitted = false;
if (writeRequest)
{
- permitted = PermissionUtil.isWritable(configuration, repository,
- securityContext);
+ permitted = PermissionUtil.isWritable(configuration, repository);
}
else
{
- permitted = PermissionUtil.hasPermission(repository, securityContext,
- PermissionType.READ);
+ permitted = PermissionUtil.hasPermission(configuration, repository,
+ PermissionType.READ);
}
return permitted;
@@ -321,9 +316,6 @@ public abstract class PermissionFilter extends HttpFilter
//~--- fields ---------------------------------------------------------------
- /** Field description */
- protected Provider securityContextProvider;
-
/** Field description */
private ScmConfiguration configuration;
}
diff --git a/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java
index 6d9abe73b1..d72b4a68b2 100644
--- a/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java
+++ b/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java
@@ -67,6 +67,21 @@ public abstract class ProviderPermissionFilter extends PermissionFilter
//~--- constructors ---------------------------------------------------------
+ /**
+ * Constructs ...
+ *
+ *
+ * @param configuration
+ * @param repositoryProvider
+ * @since 1.21
+ */
+ public ProviderPermissionFilter(ScmConfiguration configuration,
+ RepositoryProvider repositoryProvider)
+ {
+ super(configuration);
+ this.repositoryProvider = repositoryProvider;
+ }
+
/**
* Constructs ...
*
@@ -75,14 +90,14 @@ public abstract class ProviderPermissionFilter extends PermissionFilter
* @param configuration
* @param securityContextProvider
* @param repositoryProvider
+ * @deprecated
*/
- public ProviderPermissionFilter(
- ScmConfiguration configuration,
- Provider securityContextProvider,
- RepositoryProvider repositoryProvider)
+ @Deprecated
+ public ProviderPermissionFilter(ScmConfiguration configuration,
+ Provider securityContextProvider,
+ RepositoryProvider repositoryProvider)
{
- super(configuration, securityContextProvider);
- this.repositoryProvider = repositoryProvider;
+ this(configuration, repositoryProvider);
}
//~--- get methods ----------------------------------------------------------
@@ -107,7 +122,7 @@ public abstract class ProviderPermissionFilter extends PermissionFilter
catch (ProvisionException ex)
{
Throwables.propagateIfInstanceOf(ex.getCause(),
- IllegalStateException.class);
+ IllegalStateException.class);
if (logger.isErrorEnabled())
{
diff --git a/scm-core/src/main/java/sonia/scm/web/filter/RegexPermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/RegexPermissionFilter.java
index 0deac57121..a064d12115 100644
--- a/scm-core/src/main/java/sonia/scm/web/filter/RegexPermissionFilter.java
+++ b/scm-core/src/main/java/sonia/scm/web/filter/RegexPermissionFilter.java
@@ -71,15 +71,31 @@ public abstract class RegexPermissionFilter extends PermissionFilter
* @param securityContextProvider
* @param repositoryManager
*/
- public RegexPermissionFilter(
- ScmConfiguration configuration,
- Provider securityContextProvider,
- RepositoryManager repositoryManager)
+ public RegexPermissionFilter(ScmConfiguration configuration,
+ RepositoryManager repositoryManager)
{
- super(configuration, securityContextProvider);
+ super(configuration);
this.repositoryManager = repositoryManager;
}
+ /**
+ * Constructs ...
+ *
+ *
+ *
+ * @param configuration
+ * @param securityContextProvider
+ * @param repositoryManager
+ * @deprecated
+ */
+ @Deprecated
+ public RegexPermissionFilter(ScmConfiguration configuration,
+ Provider securityContextProvider,
+ RepositoryManager repositoryManager)
+ {
+ this(configuration, repositoryManager);
+ }
+
//~--- get methods ----------------------------------------------------------
/**
diff --git a/scm-core/src/main/java/sonia/scm/web/security/WebSecurityContext.java b/scm-core/src/main/java/sonia/scm/web/security/WebSecurityContext.java
index 1b9ccec280..d99716a5ff 100644
--- a/scm-core/src/main/java/sonia/scm/web/security/WebSecurityContext.java
+++ b/scm-core/src/main/java/sonia/scm/web/security/WebSecurityContext.java
@@ -44,11 +44,14 @@ import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.shiro.SecurityUtils;
/**
*
* @author Sebastian Sdorra
+ * @deprecated use {@link SecurityUtils#getSecurityManager()} instead.
*/
+@Deprecated
public interface WebSecurityContext extends SecurityContext
{
diff --git a/scm-core/src/test/java/sonia/scm/repository/PermissionUtilTest.java b/scm-core/src/test/java/sonia/scm/repository/PermissionUtilTest.java
index ae485a66bc..9c99e6a7db 100644
--- a/scm-core/src/test/java/sonia/scm/repository/PermissionUtilTest.java
+++ b/scm-core/src/test/java/sonia/scm/repository/PermissionUtilTest.java
@@ -36,6 +36,7 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import sonia.scm.config.ScmConfiguration;
@@ -58,6 +59,7 @@ import java.util.Set;
*
* @author Sebastian Sdorra
*/
+@Ignore
public class PermissionUtilTest
{
@@ -111,10 +113,8 @@ public class PermissionUtilTest
Permission[] permissions = new Permission[] {
new Permission("dent", PermissionType.READ),
- new Permission("perfect",
- PermissionType.WRITE),
- new Permission("marvin",
- PermissionType.OWNER) };
+ new Permission("perfect", PermissionType.WRITE),
+ new Permission("marvin", PermissionType.OWNER) };
repository.setPermissions(Arrays.asList(permissions));
}
@@ -139,10 +139,10 @@ public class PermissionUtilTest
Repository r = new Repository();
r.setPermissions(
- new ArrayList(
- Arrays.asList(
- new Permission("dent"),
- new Permission("devel", PermissionType.WRITE, true),
+ new ArrayList(
+ Arrays.asList(
+ new Permission("dent"),
+ new Permission("devel", PermissionType.WRITE, true),
new Permission("qa", PermissionType.READ, true))));
// member of both devel and qa
@@ -167,9 +167,9 @@ public class PermissionUtilTest
// member of no groups
assertFalse(PermissionUtil.hasPermission(r, trillian, PermissionType.READ));
assertFalse(PermissionUtil.hasPermission(r, trillian,
- PermissionType.WRITE));
+ PermissionType.WRITE));
assertFalse(PermissionUtil.hasPermission(r, trillian,
- PermissionType.OWNER));
+ PermissionType.OWNER));
}
/**
@@ -207,29 +207,29 @@ public class PermissionUtilTest
public void hasPermissionTest()
{
assertTrue(PermissionUtil.hasPermission(repository, dent,
- PermissionType.READ));
+ PermissionType.READ));
assertTrue(PermissionUtil.hasPermission(repository, perfect,
- PermissionType.READ));
+ PermissionType.READ));
assertTrue(PermissionUtil.hasPermission(repository, perfect,
- PermissionType.WRITE));
+ PermissionType.WRITE));
assertFalse(PermissionUtil.hasPermission(repository, dent,
- PermissionType.WRITE));
+ PermissionType.WRITE));
assertFalse(PermissionUtil.hasPermission(repository, slarti,
- PermissionType.WRITE));
+ PermissionType.WRITE));
assertFalse(PermissionUtil.hasPermission(repository, slarti,
- PermissionType.READ));
+ PermissionType.READ));
assertTrue(PermissionUtil.hasPermission(repository, marvin,
- PermissionType.READ));
+ PermissionType.READ));
assertTrue(PermissionUtil.hasPermission(repository, marvin,
- PermissionType.WRITE));
+ PermissionType.WRITE));
assertTrue(PermissionUtil.hasPermission(repository, marvin,
- PermissionType.OWNER));
+ PermissionType.OWNER));
assertTrue(PermissionUtil.hasPermission(repository, admams,
- PermissionType.READ));
+ PermissionType.READ));
assertTrue(PermissionUtil.hasPermission(repository, admams,
- PermissionType.WRITE));
+ PermissionType.WRITE));
assertTrue(PermissionUtil.hasPermission(repository, admams,
- PermissionType.OWNER));
+ PermissionType.OWNER));
}
//~--- methods --------------------------------------------------------------
diff --git a/scm-core/src/test/java/sonia/scm/security/RepositoryPermissionTest.java b/scm-core/src/test/java/sonia/scm/security/RepositoryPermissionTest.java
new file mode 100644
index 0000000000..e8180ca24a
--- /dev/null
+++ b/scm-core/src/test/java/sonia/scm/security/RepositoryPermissionTest.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2010, 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import org.junit.Test;
+
+import sonia.scm.repository.PermissionType;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class RepositoryPermissionTest
+{
+
+ /**
+ * Method description
+ *
+ */
+ @Test
+ public void testImplies()
+ {
+ RepositoryPermission p = new RepositoryPermission("asd",
+ PermissionType.READ);
+
+ assertTrue(p.implies(new RepositoryPermission("asd", PermissionType.READ)));
+ assertFalse(p.implies(new RepositoryPermission("asd",
+ PermissionType.OWNER)));
+ assertFalse(p.implies(new RepositoryPermission("asd",
+ PermissionType.WRITE)));
+ p = new RepositoryPermission("asd", PermissionType.OWNER);
+ assertTrue(p.implies(new RepositoryPermission("asd", PermissionType.READ)));
+ assertFalse(p.implies(new RepositoryPermission("bdb",
+ PermissionType.READ)));
+ }
+
+ /**
+ * Method description
+ *
+ */
+ @Test
+ public void testImpliesWithWildcard()
+ {
+ RepositoryPermission p = new RepositoryPermission("*",
+ PermissionType.OWNER);
+
+ assertTrue(p.implies(new RepositoryPermission("asd", PermissionType.READ)));
+ assertTrue(p.implies(new RepositoryPermission("bdb",
+ PermissionType.OWNER)));
+ assertTrue(p.implies(new RepositoryPermission("cgd",
+ PermissionType.WRITE)));
+ }
+}
diff --git a/scm-core/src/test/java/sonia/scm/template/TemplateEngineFactoryTest.java b/scm-core/src/test/java/sonia/scm/template/TemplateEngineFactoryTest.java
index b9fd7e9da6..9eb47aa061 100644
--- a/scm-core/src/test/java/sonia/scm/template/TemplateEngineFactoryTest.java
+++ b/scm-core/src/test/java/sonia/scm/template/TemplateEngineFactoryTest.java
@@ -1,34 +1,35 @@
/**
- * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ * Copyright (c) 2010, 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 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.
+ * 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.template;
//~--- non-JDK imports --------------------------------------------------------
diff --git a/scm-dao-xml/src/main/java/sonia/scm/store/JAXBStoreFactory.java b/scm-dao-xml/src/main/java/sonia/scm/store/JAXBStoreFactory.java
index 4fd7ead87b..3291be4806 100644
--- a/scm-dao-xml/src/main/java/sonia/scm/store/JAXBStoreFactory.java
+++ b/scm-dao-xml/src/main/java/sonia/scm/store/JAXBStoreFactory.java
@@ -91,7 +91,7 @@ public class JAXBStoreFactory implements ListenableStoreFactory
public void init(SCMContextProvider context)
{
configDirectory = new File(context.getBaseDirectory(),
- CONFIGDIRECTORY_NAME);
+ CONFIGDIRECTORY_NAME);
IOUtil.mkdirs(configDirectory);
}
@@ -110,12 +110,17 @@ public class JAXBStoreFactory implements ListenableStoreFactory
@Override
public JAXBStore getStore(Class type, String name)
{
+ if (configDirectory == null)
+ {
+ throw new IllegalStateException("store factory is not initialized");
+ }
+
File configFile = new File(configDirectory, name.concat(FILE_EXTENSION));
if (logger.isDebugEnabled())
{
logger.debug("create store for {} at {}", type.getName(),
- configFile.getPath());
+ configFile.getPath());
}
return new JAXBStore(type, configFile);
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java
index 6842f24566..e10568b057 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java
@@ -41,7 +41,6 @@ import com.google.inject.Singleton;
import sonia.scm.repository.RepositoryProvider;
import sonia.scm.web.filter.ProviderPermissionFilter;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -81,10 +80,9 @@ public class GitPermissionFilter extends ProviderPermissionFilter
@Inject
public GitPermissionFilter(
ScmConfiguration configuration,
- Provider securityContextProvider,
RepositoryProvider repositoryProvider)
{
- super(configuration, securityContextProvider, repositoryProvider);
+ super(configuration, repositoryProvider);
}
//~--- get methods ----------------------------------------------------------
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookCallbackServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookCallbackServlet.java
index 119ea7fcff..23ba07ffc4 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookCallbackServlet.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgHookCallbackServlet.java
@@ -39,6 +39,9 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -51,9 +54,9 @@ import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RepositoryUtil;
import sonia.scm.security.CipherUtil;
+import sonia.scm.security.Tokens;
import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -120,16 +123,14 @@ public class HgHookCallbackServlet extends HttpServlet
* @param securityContextProvider
*/
@Inject
- public HgHookCallbackServlet(
- RepositoryManager repositoryManager, HgRepositoryHandler handler,
- HgHookManager hookManager, Provider contextProvider,
- Provider securityContextProvider)
+ public HgHookCallbackServlet(RepositoryManager repositoryManager,
+ HgRepositoryHandler handler, HgHookManager hookManager,
+ Provider contextProvider)
{
this.repositoryManager = repositoryManager;
this.handler = handler;
this.hookManager = hookManager;
this.contextProvider = contextProvider;
- this.securityContextProvider = securityContextProvider;
}
//~--- methods --------------------------------------------------------------
@@ -146,7 +147,7 @@ public class HgHookCallbackServlet extends HttpServlet
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException
+ throws ServletException, IOException
{
String ping = request.getParameter(PARAM_PING);
@@ -172,8 +173,8 @@ public class HgHookCallbackServlet extends HttpServlet
*/
@Override
protected void doPost(HttpServletRequest request,
- HttpServletResponse response)
- throws ServletException, IOException
+ HttpServletResponse response)
+ throws ServletException, IOException
{
String strippedURI = HttpUtil.getStrippedURI(request);
Matcher m = REGEX_URL.matcher(strippedURI);
@@ -194,7 +195,7 @@ public class HgHookCallbackServlet extends HttpServlet
if (Util.isNotEmpty(credentials))
{
- authenticate(request, response, credentials);
+ authenticate(request, credentials);
}
hookCallback(response, repositoryId, type, challenge, node);
@@ -228,8 +229,7 @@ public class HgHookCallbackServlet extends HttpServlet
* @param response
* @param credentials
*/
- private void authenticate(HttpServletRequest request,
- HttpServletResponse response, String credentials)
+ private void authenticate(HttpServletRequest request, String credentials)
{
try
{
@@ -241,10 +241,10 @@ public class HgHookCallbackServlet extends HttpServlet
if (credentialsArray.length >= 2)
{
- WebSecurityContext context = securityContextProvider.get();
+ Subject subject = SecurityUtils.getSubject();
- context.authenticate(request, response, credentialsArray[0],
- credentialsArray[1]);
+ subject.login(Tokens.createAuthenticationToken(request,
+ credentialsArray[0], credentialsArray[1]));
}
}
}
@@ -266,8 +266,8 @@ public class HgHookCallbackServlet extends HttpServlet
* @throws IOException
*/
private void fireHook(HttpServletResponse response, String repositoryName,
- String node, RepositoryHookType type)
- throws IOException
+ String node, RepositoryHookType type)
+ throws IOException
{
try
{
@@ -277,9 +277,8 @@ public class HgHookCallbackServlet extends HttpServlet
}
repositoryManager.fireHookEvent(HgRepositoryHandler.TYPE_NAME,
- repositoryName,
- new HgRepositoryHookEvent(handler,
- repositoryName, node, type));
+ repositoryName,
+ new HgRepositoryHookEvent(handler, repositoryName, node, type));
}
catch (RepositoryNotFoundException ex)
{
@@ -310,9 +309,8 @@ public class HgHookCallbackServlet extends HttpServlet
* @throws IOException
*/
private void hookCallback(HttpServletResponse response,
- String repositoryName, String typeName,
- String challenge, String node)
- throws IOException
+ String repositoryName, String typeName, String challenge, String node)
+ throws IOException
{
if (hookManager.isAcceptAble(challenge))
{
@@ -404,7 +402,4 @@ public class HgHookCallbackServlet extends HttpServlet
/** Field description */
private RepositoryManager repositoryManager;
-
- /** Field description */
- private Provider securityContextProvider;
}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java
index 5df19d5042..73d20530ea 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java
@@ -36,17 +36,15 @@ package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
+import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.RepositoryProvider;
import sonia.scm.web.filter.ProviderPermissionFilter;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
import javax.servlet.http.HttpServletRequest;
-import sonia.scm.config.ScmConfiguration;
/**
*
@@ -61,15 +59,15 @@ public class HgPermissionFilter extends ProviderPermissionFilter
*
*
* @param securityContextProvider
+ *
+ * @param configuration
* @param repositoryProvider
*/
@Inject
- public HgPermissionFilter(
- ScmConfiguration configuration,
- Provider securityContextProvider,
- RepositoryProvider repositoryProvider)
+ public HgPermissionFilter(ScmConfiguration configuration,
+ RepositoryProvider repositoryProvider)
{
- super(configuration, securityContextProvider, repositoryProvider);
+ super(configuration, repositoryProvider);
}
//~--- get methods ----------------------------------------------------------
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java
index d5a8941552..164ccfd173 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java
@@ -37,13 +37,11 @@ package sonia.scm.web;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.RepositoryProvider;
import sonia.scm.web.filter.ProviderPermissionFilter;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -79,12 +77,10 @@ public class SvnPermissionFilter extends ProviderPermissionFilter
* @param repository
*/
@Inject
- public SvnPermissionFilter(
- ScmConfiguration configuration,
- Provider securityContextProvider,
- RepositoryProvider repository)
+ public SvnPermissionFilter(ScmConfiguration configuration,
+ RepositoryProvider repository)
{
- super(configuration, securityContextProvider, repository);
+ super(configuration, repository);
}
//~--- get methods ----------------------------------------------------------
diff --git a/scm-samples/scm-sample-hello/src/main/java/sample/hello/HelloResource.java b/scm-samples/scm-sample-hello/src/main/java/sample/hello/HelloResource.java
index a83024f4bd..2064c7ffc0 100644
--- a/scm-samples/scm-sample-hello/src/main/java/sample/hello/HelloResource.java
+++ b/scm-samples/scm-sample-hello/src/main/java/sample/hello/HelloResource.java
@@ -35,10 +35,10 @@ package sample.hello;
//~--- non-JDK imports --------------------------------------------------------
-import com.google.inject.Inject;
-import com.google.inject.Provider;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
-import sonia.scm.security.SecurityContext;
+import sonia.scm.user.User;
//~--- JDK imports ------------------------------------------------------------
@@ -61,11 +61,18 @@ public class HelloResource
*
* @param securityContextProvider
*/
- @Inject
- public HelloResource(Provider securityContextProvider)
+ public HelloResource()
{
- message = "Hello "
- + securityContextProvider.get().getUser().getDisplayName();
+ Subject subject = SecurityUtils.getSubject();
+ String displayName = "Unknown";
+
+ if (subject.isAuthenticated())
+ {
+ displayName =
+ subject.getPrincipals().oneByType(User.class).getDisplayName();
+ }
+
+ message = "Hello " + displayName;
}
//~--- get methods ----------------------------------------------------------
diff --git a/scm-test/src/main/java/sonia/scm/AbstractTestBase.java b/scm-test/src/main/java/sonia/scm/AbstractTestBase.java
index d35ac129ee..2a8a43ad7a 100644
--- a/scm-test/src/main/java/sonia/scm/AbstractTestBase.java
+++ b/scm-test/src/main/java/sonia/scm/AbstractTestBase.java
@@ -35,7 +35,15 @@ package sonia.scm;
//~--- non-JDK imports --------------------------------------------------------
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.UnavailableSecurityManagerException;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.subject.support.SubjectThreadState;
+import org.apache.shiro.util.LifecycleUtils;
+import org.apache.shiro.util.ThreadState;
+
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
import sonia.scm.util.IOUtil;
@@ -56,6 +64,81 @@ import java.util.UUID;
public class AbstractTestBase
{
+ /** Field description */
+ private static ThreadState subjectThreadState;
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ */
+ @AfterClass
+ public static void tearDownShiro()
+ {
+ doClearSubject();
+
+ try
+ {
+ org.apache.shiro.mgt.SecurityManager securityManager =
+ getSecurityManager();
+
+ LifecycleUtils.destroy(securityManager);
+ }
+ catch (UnavailableSecurityManagerException e)
+ {
+
+ // we don't care about this when cleaning up the test environment
+ // (for example, maybe the subclass is a unit test and it didn't
+ // need a SecurityManager instance because it was using only
+ // mock Subject instances)
+ }
+
+ setSecurityManager(null);
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ protected static org.apache.shiro.mgt.SecurityManager getSecurityManager()
+ {
+ return SecurityUtils.getSecurityManager();
+ }
+
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param securityManager
+ */
+ protected static void setSecurityManager(
+ org.apache.shiro.mgt.SecurityManager securityManager)
+ {
+ SecurityUtils.setSecurityManager(securityManager);
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ */
+ private static void doClearSubject()
+ {
+ if (subjectThreadState != null)
+ {
+ subjectThreadState.clear();
+ subjectThreadState = null;
+ }
+ }
+
/**
* Method description
*
@@ -87,7 +170,7 @@ public class AbstractTestBase
public void setUpTest() throws Exception
{
tempDirectory = new File(System.getProperty("java.io.tmpdir"),
- UUID.randomUUID().toString());
+ UUID.randomUUID().toString());
assertTrue(tempDirectory.mkdirs());
contextProvider = MockUtil.getSCMContextProvider(tempDirectory);
postSetUp();
@@ -95,6 +178,27 @@ public class AbstractTestBase
//~--- methods --------------------------------------------------------------
+ /**
+ * Clears Shiro's thread state, ensuring the thread remains clean for future test execution.
+ */
+ protected void clearSubject()
+ {
+ doClearSubject();
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param subject
+ *
+ * @return
+ */
+ protected ThreadState createThreadState(Subject subject)
+ {
+ return new SubjectThreadState(subject);
+ }
+
/**
* Method description
*
@@ -111,6 +215,33 @@ public class AbstractTestBase
*/
protected void preTearDown() throws Exception {}
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ protected Subject getSubject()
+ {
+ return SecurityUtils.getSubject();
+ }
+
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Allows subclasses to set the currently executing {@link Subject} instance.
+ *
+ * @param subject the Subject instance
+ */
+ protected void setSubject(Subject subject)
+ {
+ clearSubject();
+ subjectThreadState = createThreadState(subject);
+ subjectThreadState.bind();
+ }
+
;
//~--- fields ---------------------------------------------------------------
diff --git a/scm-test/src/main/java/sonia/scm/user/UserManagerTestBase.java b/scm-test/src/main/java/sonia/scm/user/UserManagerTestBase.java
index f3594e2987..2841eafe72 100644
--- a/scm-test/src/main/java/sonia/scm/user/UserManagerTestBase.java
+++ b/scm-test/src/main/java/sonia/scm/user/UserManagerTestBase.java
@@ -35,6 +35,9 @@ package sonia.scm.user;
//~--- non-JDK imports --------------------------------------------------------
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
import org.junit.Test;
import sonia.scm.Manager;
@@ -56,7 +59,7 @@ import java.util.UUID;
* @author Sebastian Sdorra
*/
public abstract class UserManagerTestBase
- extends ManagerTestBase
+ extends ManagerTestBase
{
/** Field description */
@@ -265,7 +268,7 @@ public abstract class UserManagerTestBase
*/
@Test
public void testMultiThreaded()
- throws UserException, IOException, InterruptedException
+ throws UserException, IOException, InterruptedException
{
int initialSize = manager.getAll().size();
List testers = new ArrayList();
@@ -275,8 +278,11 @@ public abstract class UserManagerTestBase
testers.add(new MultiThreadTester(manager));
}
+ Subject subject = SecurityUtils.getSubject();
+
for (MultiThreadTester tester : testers)
{
+ subject.associateWith(tester);
new Thread(tester).start();
}
@@ -393,7 +399,7 @@ public abstract class UserManagerTestBase
{
String id = UUID.randomUUID().toString();
User user = new User(id, id.concat(" displayName"),
- id.concat("@mail.com"));
+ id.concat("@mail.com"));
manager.create(user);
@@ -410,7 +416,7 @@ public abstract class UserManagerTestBase
* @throws UserException
*/
private void modifyAndDeleteUser(User user)
- throws UserException, IOException
+ throws UserException, IOException
{
String name = user.getName();
String nd = name.concat(" new displayname");
diff --git a/scm-test/src/main/java/sonia/scm/util/MockUtil.java b/scm-test/src/main/java/sonia/scm/util/MockUtil.java
index ba6d9c74f5..bb6a0a1ca8 100644
--- a/scm-test/src/main/java/sonia/scm/util/MockUtil.java
+++ b/scm-test/src/main/java/sonia/scm/util/MockUtil.java
@@ -37,6 +37,13 @@ package sonia.scm.util;
import com.google.inject.Provider;
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.Subject;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
import sonia.scm.SCMContextProvider;
import sonia.scm.user.User;
import sonia.scm.web.security.DummyWebSecurityContext;
@@ -48,6 +55,9 @@ import static org.mockito.Mockito.*;
import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -58,6 +68,59 @@ import javax.servlet.http.HttpServletResponse;
public class MockUtil
{
+ /** Field description */
+ private static final User ADMIN = new User("scmadmin", "SCM Admin",
+ "scmadmin@scm.org");
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public static Subject createAdminSubject()
+ {
+ Subject subject = mock(Subject.class);
+
+ when(subject.isAuthenticated()).thenReturn(Boolean.TRUE);
+ when(subject.isPermitted(anyListOf(Permission.class))).then(
+ new Answer()
+ {
+
+ @Override
+ public Boolean[] answer(InvocationOnMock invocation) throws Throwable
+ {
+ List permissions =
+ (List) invocation.getArguments()[0];
+ Boolean[] returnArray = new Boolean[permissions.size()];
+
+ Arrays.fill(returnArray, Boolean.TRUE);
+
+ return returnArray;
+ }
+ });
+ when(subject.isPermitted(any(Permission.class))).thenReturn(Boolean.TRUE);
+ when(subject.isPermitted(any(String.class))).thenReturn(Boolean.TRUE);
+ when(subject.isPermittedAll(anyCollectionOf(Permission.class))).thenReturn(
+ Boolean.TRUE);
+ when(subject.isPermittedAll()).thenReturn(Boolean.TRUE);
+ when(subject.hasRole("admin")).thenReturn(Boolean.TRUE);
+
+ PrincipalCollection collection = mock(PrincipalCollection.class);
+
+ when(collection.getPrimaryPrincipal()).thenReturn(ADMIN.getId());
+ when(collection.oneByType(User.class)).thenReturn(ADMIN);
+
+ when(subject.getPrincipal()).thenReturn(ADMIN.getId());
+ when(subject.getPrincipals()).thenReturn(collection);
+
+ return subject;
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
/**
* Method description
*
diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml
index e08eb823fb..6fde5319b1 100644
--- a/scm-webapp/pom.xml
+++ b/scm-webapp/pom.xml
@@ -64,6 +64,20 @@
scm-git-plugin
1.21-SNAPSHOT
+
+
+
+
+ org.apache.shiro
+ shiro-web
+ ${shiro.version}
+
+
+
+ org.apache.shiro
+ shiro-guice
+ ${shiro.version}
+
diff --git a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java
index 54b146a4d8..2a876502a2 100644
--- a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java
+++ b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java
@@ -35,11 +35,14 @@ package sonia.scm;
//~--- non-JDK imports --------------------------------------------------------
+import com.google.common.collect.Lists;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.servlet.GuiceServletContextListener;
+import org.apache.shiro.guice.web.ShiroWebModule;
+
import sonia.scm.cache.CacheManager;
import sonia.scm.group.GroupManager;
import sonia.scm.plugin.DefaultPluginLoader;
@@ -49,13 +52,12 @@ import sonia.scm.store.StoreFactory;
import sonia.scm.user.UserManager;
import sonia.scm.util.IOUtil;
import sonia.scm.web.security.AuthenticationManager;
-import sonia.scm.web.security.LocalSecurityContextHolder;
//~--- JDK imports ------------------------------------------------------------
-import java.util.ArrayList;
import java.util.List;
+import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
/**
@@ -95,13 +97,10 @@ public class ScmContextListener extends GuiceServletContextListener
// close CacheManager
IOUtil.close(globalInjector.getInstance(CacheManager.class));
- // remove thread local store
- globalInjector.getInstance(LocalSecurityContextHolder.class).destroy();
-
// call destroy event
globalInjector.getInstance(
- ServletContextListenerHolder.class).contextDestroyed(
- servletContextEvent);
+ ServletContextListenerHolder.class).contextDestroyed(
+ servletContextEvent);
}
super.contextDestroyed(servletContextEvent);
@@ -116,6 +115,8 @@ public class ScmContextListener extends GuiceServletContextListener
@Override
public void contextInitialized(ServletContextEvent servletContextEvent)
{
+ this.servletContext = servletContextEvent.getServletContext();
+
if (SCMContext.getContext().getStartupError() == null)
{
ScmUpgradeHandler upgradeHandler = new ScmUpgradeHandler();
@@ -133,8 +134,8 @@ public class ScmContextListener extends GuiceServletContextListener
if ((globalInjector != null) &&!startupError)
{
globalInjector.getInstance(
- ServletContextListenerHolder.class).contextInitialized(
- servletContextEvent);
+ ServletContextListenerHolder.class).contextInitialized(
+ servletContextEvent);
}
}
@@ -155,7 +156,7 @@ public class ScmContextListener extends GuiceServletContextListener
}
else
{
- globalInjector = getDefaultInjector();
+ globalInjector = getDefaultInjector(servletContext);
}
return globalInjector;
@@ -165,9 +166,11 @@ public class ScmContextListener extends GuiceServletContextListener
* Method description
*
*
+ *
+ * @param servletContext
* @return
*/
- private Injector getDefaultInjector()
+ private Injector getDefaultInjector(ServletContext servletContext)
{
PluginLoader pluginLoader = new DefaultPluginLoader();
BindingExtensionProcessor bindExtProcessor =
@@ -178,42 +181,16 @@ public class ScmContextListener extends GuiceServletContextListener
ClassOverrides overrides = ClassOverrides.findOverrides();
ScmServletModule main = new ScmServletModule(pluginLoader,
bindExtProcessor, overrides);
- List moduleList = new ArrayList();
+ List moduleList = Lists.newArrayList();
+ moduleList.add(new ScmInitializerModule());
+ moduleList.add(ShiroWebModule.guiceFilterModule());
+ moduleList.add(main);
+ moduleList.add(new ScmSecurityModule(servletContext));
moduleList.addAll(bindExtProcessor.getModuleSet());
moduleList.addAll(overrides.getModules());
- moduleList.add(0, main);
- Injector injector = Guice.createInjector(moduleList);
- SCMContextProvider context = SCMContext.getContext();
-
- // init StoreFactory
- injector.getInstance(StoreFactory.class).init(context);
-
- // init RepositoryManager
- RepositoryManager repositoryManager =
- injector.getInstance(RepositoryManager.class);
-
- repositoryManager.addHooks(bindExtProcessor.getHooks());
- repositoryManager.init(context);
-
- // init UserManager
- UserManager userManager = injector.getInstance(UserManager.class);
-
- userManager.init(context);
-
- // init GroupManager
- GroupManager groupManager = injector.getInstance(GroupManager.class);
-
- groupManager.init(context);
-
- // init Authenticator
- AuthenticationManager authenticationManager =
- injector.getInstance(AuthenticationManager.class);
-
- authenticationManager.init(context);
-
- return injector;
+ return Guice.createInjector(moduleList);
}
/**
@@ -232,6 +209,9 @@ public class ScmContextListener extends GuiceServletContextListener
/** Field description */
private Injector globalInjector;
+ /** Field description */
+ private ServletContext servletContext;
+
/** Field description */
private boolean startupError = false;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/ScmInitializerModule.java b/scm-webapp/src/main/java/sonia/scm/ScmInitializerModule.java
new file mode 100644
index 0000000000..16675749ac
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/ScmInitializerModule.java
@@ -0,0 +1,149 @@
+/**
+ * Copyright (c) 2010, 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.AbstractModule;
+import com.google.inject.TypeLiteral;
+import com.google.inject.matcher.AbstractMatcher;
+import com.google.inject.matcher.Matcher;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.TypeEncounter;
+import com.google.inject.spi.TypeListener;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class ScmInitializerModule extends AbstractModule
+{
+
+ /**
+ * the logger for ScmInitializerModule
+ */
+ private static final Logger logger =
+ LoggerFactory.getLogger(ScmInitializerModule.class);
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ */
+ @Override
+ protected void configure()
+ {
+ bindListener(isSubtypeOf(Initable.class), new TypeListener()
+ {
+
+ @Override
+ public void hear(TypeLiteral type, TypeEncounter encounter)
+ {
+ encounter.register(new InjectionListener()
+ {
+ @Override
+ public void afterInjection(Object i)
+ {
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("initialize initable {}", i.getClass());
+ }
+
+ Initable initable = (Initable) i;
+
+ initable.init(SCMContext.getContext());
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param subtype
+ * @param supertype
+ *
+ * @return
+ */
+ private boolean typeIsSubtypeOf(TypeLiteral> subtype,
+ TypeLiteral> supertype)
+ {
+
+ // First check that raw types are compatible
+ // Then check that generic types are compatible! HOW????
+ return (subtype.equals(supertype)
+ || (supertype.getRawType().isAssignableFrom(subtype.getRawType())
+ && supertype.equals(subtype.getSupertype(supertype.getRawType()))));
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param supertype
+ *
+ * @return
+ */
+ private Matcher> isSubtypeOf(final Class> supertype)
+ {
+ return isSubtypeOf(TypeLiteral.get(supertype));
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param supertype
+ *
+ * @return
+ */
+ private Matcher> isSubtypeOf(final TypeLiteral> supertype)
+ {
+ return new AbstractMatcher>()
+ {
+ @Override
+ public boolean matches(TypeLiteral> type)
+ {
+ return typeIsSubtypeOf(type, supertype);
+ }
+ };
+ }
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/LocalSecurityContextHolder.java b/scm-webapp/src/main/java/sonia/scm/ScmSecurityModule.java
similarity index 68%
rename from scm-webapp/src/main/java/sonia/scm/web/security/LocalSecurityContextHolder.java
rename to scm-webapp/src/main/java/sonia/scm/ScmSecurityModule.java
index 6f0277f25a..50d3184b3a 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/security/LocalSecurityContextHolder.java
+++ b/scm-webapp/src/main/java/sonia/scm/ScmSecurityModule.java
@@ -30,67 +30,45 @@
*/
+package sonia.scm;
-package sonia.scm.web.security;
+//~--- non-JDK imports --------------------------------------------------------
-import com.google.inject.Singleton;
+import org.apache.shiro.guice.web.ShiroWebModule;
+
+import sonia.scm.security.ScmRealm;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.servlet.ServletContext;
/**
*
* @author Sebastian Sdorra
*/
-@Singleton
-public class LocalSecurityContextHolder
+public class ScmSecurityModule extends ShiroWebModule
{
/**
- * Method description
+ * Constructs ...
*
+ *
+ * @param servletContext
*/
- public void destroy()
+ ScmSecurityModule(ServletContext servletContext)
{
- store.remove();
- store = null;
+ super(servletContext);
}
+ //~--- methods --------------------------------------------------------------
+
/**
* Method description
*
*/
- public void remove()
+ @Override
+ protected void configureShiroWeb()
{
- store.remove();
+ bindRealm().to(ScmRealm.class);
}
-
- //~--- get methods ----------------------------------------------------------
-
- /**
- * Method description
- *
- *
- * @return
- */
- public WebSecurityContext get()
- {
- return store.get();
- }
-
- //~--- set methods ----------------------------------------------------------
-
- /**
- * Method description
- *
- *
- * @param value
- */
- public void set(WebSecurityContext value)
- {
- store.set(value);
- }
-
- //~--- fields ---------------------------------------------------------------
-
- /** Field description */
- private ThreadLocal store =
- new ThreadLocal();
}
diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java
index 5a9da3c222..c20aad948e 100644
--- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java
+++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java
@@ -116,8 +116,6 @@ import sonia.scm.web.security.AuthenticationManager;
import sonia.scm.web.security.BasicSecurityContext;
import sonia.scm.web.security.ChainAuthenticatonManager;
import sonia.scm.web.security.DefaultAdministrationContext;
-import sonia.scm.web.security.LocalSecurityContextHolder;
-import sonia.scm.web.security.SecurityContextProvider;
import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -264,11 +262,8 @@ public class ScmServletModule extends ServletModule
// bind security stuff
bind(AuthenticationManager.class, ChainAuthenticatonManager.class);
- bind(LocalSecurityContextHolder.class);
- bind(WebSecurityContext.class).annotatedWith(Names.named("userSession")).to(
- BasicSecurityContext.class);
- bind(SecurityContext.class).toProvider(SecurityContextProvider.class);
- bind(WebSecurityContext.class).toProvider(SecurityContextProvider.class);
+ bind(SecurityContext.class).to(BasicSecurityContext.class);
+ bind(WebSecurityContext.class).to(BasicSecurityContext.class);
bind(AdministrationContext.class, DefaultAdministrationContext.class);
// bind security cache
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java
index 9dc0277fc7..150d352219 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java
@@ -36,9 +36,13 @@ package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.Subject;
+
import org.codehaus.enunciate.jaxrs.TypeHint;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
@@ -50,13 +54,17 @@ import sonia.scm.SCMContextProvider;
import sonia.scm.ScmClientConfig;
import sonia.scm.ScmState;
import sonia.scm.config.ScmConfiguration;
+import sonia.scm.group.GroupNames;
import sonia.scm.repository.RepositoryManager;
+import sonia.scm.security.Tokens;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
+import java.util.Collection;
+import java.util.Collections;
+
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -98,16 +106,14 @@ public class AuthenticationResource
* @param securityContextProvider
*/
@Inject
- public AuthenticationResource(
- SCMContextProvider contextProvider, ScmConfiguration configuration,
- RepositoryManager repositoryManger, UserManager userManager,
- Provider securityContextProvider)
+ public AuthenticationResource(SCMContextProvider contextProvider,
+ ScmConfiguration configuration, RepositoryManager repositoryManger,
+ UserManager userManager)
{
this.contextProvider = contextProvider;
this.configuration = configuration;
this.repositoryManger = repositoryManger;
this.userManager = userManager;
- this.securityContextProvider = securityContextProvider;
}
//~--- methods --------------------------------------------------------------
@@ -132,21 +138,30 @@ public class AuthenticationResource
@Path("login")
@TypeHint(ScmState.class)
public ScmState authenticate(@Context HttpServletRequest request,
- @Context HttpServletResponse response,
- @FormParam("username") String username,
- @FormParam("password") String password)
+ @FormParam("username") String username,
+ @FormParam("password") String password)
{
ScmState state = null;
- WebSecurityContext securityContext = securityContextProvider.get();
- User user = securityContext.authenticate(request, response, username,
- password);
- if ((user != null) &&!SCMContext.USER_ANONYMOUS.equals(user.getName()))
+ Subject subject = SecurityUtils.getSubject();
+
+ try
{
- state = createState(securityContext);
+ subject.login(Tokens.createAuthenticationToken(request, username,
+ password));
+ state = createState(subject);
}
- else
+ catch (AuthenticationException ex)
{
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("authentication failed for user ".concat(username), ex);
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("authentication failed for user {}", username);
+ }
+
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
@@ -171,20 +186,18 @@ public class AuthenticationResource
@Path("logout")
@TypeHint(ScmState.class)
public Response logout(@Context HttpServletRequest request,
- @Context HttpServletResponse response)
+ @Context HttpServletResponse response)
{
- WebSecurityContext securityContext = securityContextProvider.get();
+ Subject subject = SecurityUtils.getSubject();
- securityContext.logout(request, response);
+ subject.logout();
Response resp = null;
- User user = securityContext.getUser();
- if (user != null)
+ if (configuration.isAnonymousAccessEnabled())
{
- ScmState state = createState(securityContext);
- resp = Response.ok(state).build();
+ resp = Response.ok(createAnonymousState()).build();
}
else
{
@@ -238,20 +251,24 @@ public class AuthenticationResource
public Response getState(@Context HttpServletRequest request)
{
Response response = null;
- ScmState state = null;
- WebSecurityContext securityContext = securityContextProvider.get();
- User user = securityContext.getUser();
+ Subject subject = SecurityUtils.getSubject();
- if (user != null)
+ if (subject.isAuthenticated())
{
if (logger.isDebugEnabled())
{
- logger.debug("return state for user {}", user.getName());
+ logger.debug("return state for user {}", subject.getPrincipal());
}
- state = createState(securityContext);
+ ScmState state = createState(subject);
+
response = Response.ok(state).build();
}
+ else if (configuration.isAnonymousAccessEnabled())
+ {
+
+ response = Response.ok(createAnonymousState()).build();
+ }
else
{
response = Response.status(Response.Status.UNAUTHORIZED).build();
@@ -262,20 +279,50 @@ public class AuthenticationResource
//~--- methods --------------------------------------------------------------
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ private ScmState createAnonymousState()
+ {
+ return createState(SCMContext.ANONYMOUS, Collections.EMPTY_LIST);
+ }
+
/**
* Method description
*
*
* @param securityContext
*
+ * @param subject
+ *
* @return
*/
- private ScmState createState(WebSecurityContext securityContext)
+ private ScmState createState(Subject subject)
{
- return new ScmState(contextProvider, securityContext,
- repositoryManger.getConfiguredTypes(),
- userManager.getDefaultType(),
- new ScmClientConfig(configuration));
+ PrincipalCollection collection = subject.getPrincipals();
+ User user = collection.oneByType(User.class);
+ GroupNames groups = collection.oneByType(GroupNames.class);
+
+ return createState(user, groups.getCollection());
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param user
+ * @param groups
+ *
+ * @return
+ */
+ private ScmState createState(User user, Collection groups)
+ {
+ return new ScmState(contextProvider, user, groups,
+ repositoryManger.getConfiguredTypes(), userManager.getDefaultType(),
+ new ScmClientConfig(configuration));
}
//~--- fields ---------------------------------------------------------------
@@ -289,9 +336,6 @@ public class AuthenticationResource
/** Field description */
private RepositoryManager repositoryManger;
- /** Field description */
- private Provider securityContextProvider;
-
/** Field description */
private UserManager userManager;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java
index 9b4b05c43e..48c63b3b0a 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java
@@ -36,7 +36,9 @@ package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
-import com.google.inject.Provider;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
import org.codehaus.enunciate.jaxrs.TypeHint;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
@@ -46,11 +48,11 @@ import org.slf4j.LoggerFactory;
import sonia.scm.api.rest.RestActionResult;
import sonia.scm.security.EncryptionHandler;
+import sonia.scm.security.ScmSecurityException;
import sonia.scm.user.User;
import sonia.scm.user.UserException;
import sonia.scm.user.UserManager;
import sonia.scm.util.AssertUtil;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -88,13 +90,11 @@ public class ChangePasswordResource
* @param securityContextProvider
*/
@Inject
- public ChangePasswordResource(
- UserManager userManager, EncryptionHandler encryptionHandler,
- Provider securityContextProvider)
+ public ChangePasswordResource(UserManager userManager,
+ EncryptionHandler encryptionHandler)
{
this.userManager = userManager;
this.encryptionHandler = encryptionHandler;
- this.securityContextProvider = securityContextProvider;
}
//~--- methods --------------------------------------------------------------
@@ -121,8 +121,8 @@ public class ChangePasswordResource
@TypeHint(RestActionResult.class)
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response changePassword(@FormParam("old-password") String oldPassword,
- @FormParam("new-password") String newPassword)
- throws UserException, IOException
+ @FormParam("new-password") String newPassword)
+ throws UserException, IOException
{
AssertUtil.assertIsNotEmpty(oldPassword);
AssertUtil.assertIsNotEmpty(newPassword);
@@ -135,8 +135,14 @@ public class ChangePasswordResource
}
Response response = null;
- WebSecurityContext securityContext = securityContextProvider.get();
- User currentUser = securityContext.getUser();
+ Subject subject = SecurityUtils.getSubject();
+
+ if (!subject.isAuthenticated())
+ {
+ throw new ScmSecurityException("user is not authenticated");
+ }
+
+ User currentUser = subject.getPrincipals().oneByType(User.class);
if (logger.isInfoEnabled())
{
@@ -178,9 +184,6 @@ public class ChangePasswordResource
/** Field description */
private EncryptionHandler encryptionHandler;
- /** Field description */
- private Provider securityContextProvider;
-
/** Field description */
private UserManager userManager;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java
index 36cd0d149a..6c888470ad 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ConfigurationResource.java
@@ -36,15 +36,17 @@ package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
import sonia.scm.config.ScmConfiguration;
+import sonia.scm.security.Role;
+import sonia.scm.security.ScmSecurityException;
import sonia.scm.util.ScmConfigurationUtil;
-import sonia.scm.util.SecurityUtil;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -76,11 +78,8 @@ public class ConfigurationResource
* @param securityContextProvider
*/
@Inject
- public ConfigurationResource(
- Provider securityContextProvider,
- ScmConfiguration configuration)
+ public ConfigurationResource(ScmConfiguration configuration)
{
- this.securityContextProvider = securityContextProvider;
this.configuration = configuration;
}
@@ -98,7 +97,7 @@ public class ConfigurationResource
{
Response response = null;
- if (SecurityUtil.isAdmin(securityContextProvider))
+ if (SecurityUtils.getSubject().hasRole(Role.ADMIN))
{
response = Response.ok(configuration).build();
}
@@ -124,9 +123,17 @@ public class ConfigurationResource
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response setConfig(@Context UriInfo uriInfo,
- ScmConfiguration newConfig)
+ ScmConfiguration newConfig)
{
- SecurityUtil.assertIsAdmin(securityContextProvider);
+
+ // TODO replace by checkRole
+ Subject subject = SecurityUtils.getSubject();
+
+ if (!subject.hasRole(Role.ADMIN))
+ {
+ throw new ScmSecurityException("admin privileges required");
+ }
+
configuration.load(newConfig);
synchronized (ScmConfiguration.class)
@@ -141,7 +148,4 @@ public class ConfigurationResource
/** Field description */
public ScmConfiguration configuration;
-
- /** Field description */
- private Provider securityContextProvider;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java
index f542195bf4..f1a4d19ff3 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/GroupResource.java
@@ -39,14 +39,15 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+
import org.codehaus.enunciate.jaxrs.TypeHint;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
import sonia.scm.group.Group;
import sonia.scm.group.GroupException;
import sonia.scm.group.GroupManager;
-import sonia.scm.util.SecurityUtil;
-import sonia.scm.web.security.WebSecurityContext;
+import sonia.scm.security.Role;
//~--- JDK imports ------------------------------------------------------------
@@ -77,7 +78,7 @@ import javax.ws.rs.core.UriInfo;
@Singleton
@ExternallyManagedLifecycle
public class GroupResource
- extends AbstractManagerResource
+ extends AbstractManagerResource
{
/** Field description */
@@ -94,11 +95,9 @@ public class GroupResource
* @param groupManager
*/
@Inject
- public GroupResource(Provider securityContextProvider,
- GroupManager groupManager)
+ public GroupResource(GroupManager groupManager)
{
super(groupManager);
- this.securityContextProvider = securityContextProvider;
}
//~--- methods --------------------------------------------------------------
@@ -172,7 +171,7 @@ public class GroupResource
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override
public Response update(@Context UriInfo uriInfo,
- @PathParam("id") String name, Group group)
+ @PathParam("id") String name, Group group)
{
return super.update(uriInfo, name, group);
}
@@ -205,7 +204,7 @@ public class GroupResource
{
Response response = null;
- if (SecurityUtil.isAdmin(securityContextProvider))
+ if (SecurityUtils.getSubject().hasRole(Role.ADMIN))
{
response = super.get(request, id);
}
@@ -243,7 +242,7 @@ public class GroupResource
public Response getAll(@Context Request request, @DefaultValue("0")
@QueryParam("start") int start, @DefaultValue("-1")
@QueryParam("limit") int limit, @QueryParam("sortby") String sortby,
- @DefaultValue("false")
+ @DefaultValue("false")
@QueryParam("desc") boolean desc)
{
return super.getAll(request, start, limit, sortby, desc);
@@ -261,7 +260,7 @@ public class GroupResource
*/
@Override
protected GenericEntity> createGenericEntity(
- Collection items)
+ Collection items)
{
return new GenericEntity>(items) {}
;
@@ -294,9 +293,4 @@ public class GroupResource
{
return PATH_PART;
}
-
- //~--- fields ---------------------------------------------------------------
-
- /** Field description */
- private Provider securityContextProvider;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java
index 4462f28c2d..b3a994112a 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java
@@ -30,12 +30,12 @@
*/
+
package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.codehaus.enunciate.jaxrs.TypeHint;
@@ -50,7 +50,6 @@ import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryHandler;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.util.SecurityUtil;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -93,12 +92,9 @@ public class RepositoryImportResource
* @param securityContextProvider
*/
@Inject
- public RepositoryImportResource(
- RepositoryManager manager,
- Provider securityContextProvider)
+ public RepositoryImportResource(RepositoryManager manager)
{
this.manager = manager;
- this.securityContextProvider = securityContextProvider;
}
//~--- methods --------------------------------------------------------------
@@ -116,9 +112,9 @@ public class RepositoryImportResource
@TypeHint(Repository[].class)
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public GenericEntity> importRepositories(
- @PathParam("type") String type)
+ @PathParam("type") String type)
{
- SecurityUtil.assertIsAdmin(securityContextProvider);
+ SecurityUtil.assertIsAdmin();
List repositories = new ArrayList();
RepositoryHandler handler = manager.getHandler(type);
@@ -143,7 +139,7 @@ public class RepositoryImportResource
else if (logger.isWarnEnabled())
{
logger.warn("could not find imported repository {}",
- repositoryName);
+ repositoryName);
}
}
}
@@ -175,7 +171,7 @@ public class RepositoryImportResource
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public GenericEntity> getImportableTypes()
{
- SecurityUtil.assertIsAdmin(securityContextProvider);
+ SecurityUtil.assertIsAdmin();
List types = new ArrayList();
Collection handlerTypes = manager.getTypes();
@@ -202,7 +198,7 @@ public class RepositoryImportResource
else if (logger.isInfoEnabled())
{
logger.info("{} handler does not support import of repositories",
- t.getName());
+ t.getName());
}
}
}
@@ -220,7 +216,4 @@ public class RepositoryImportResource
/** Field description */
private RepositoryManager manager;
-
- /** Field description */
- private Provider securityContextProvider;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java
index a8adf22f6e..7801abf7b2 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java
@@ -38,9 +38,10 @@ package sonia.scm.api.rest.resources;
import com.google.common.base.Strings;
import com.google.common.io.Closeables;
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+
import org.codehaus.enunciate.jaxrs.TypeHint;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
@@ -55,7 +56,6 @@ import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.Permission;
import sonia.scm.repository.PermissionType;
-import sonia.scm.repository.PermissionUtil;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RepositoryIsNotArchivedException;
@@ -71,10 +71,10 @@ import sonia.scm.repository.api.DiffCommandBuilder;
import sonia.scm.repository.api.LogCommandBuilder;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
+import sonia.scm.security.RepositoryPermission;
import sonia.scm.security.ScmSecurityException;
import sonia.scm.util.AssertUtil;
import sonia.scm.util.Util;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -137,14 +137,12 @@ public class RepositoryResource
@Inject
public RepositoryResource(ScmConfiguration configuration,
RepositoryManager repositoryManager,
- Provider securityContextProvider,
RepositoryServiceFactory servicefactory)
{
super(repositoryManager);
this.configuration = configuration;
this.repositoryManager = repositoryManager;
this.servicefactory = servicefactory;
- this.securityContextProvider = securityContextProvider;
setDisableCache(false);
}
@@ -1091,8 +1089,9 @@ public class RepositoryResource
*/
private boolean isOwner(Repository repository)
{
- return PermissionUtil.hasPermission(repository, securityContextProvider,
- PermissionType.OWNER);
+
+ return SecurityUtils.getSubject().isPermitted(
+ new RepositoryPermission(repository, PermissionType.OWNER));
}
//~--- fields ---------------------------------------------------------------
@@ -1103,9 +1102,6 @@ public class RepositoryResource
/** Field description */
private RepositoryManager repositoryManager;
- /** Field description */
- private Provider securityContextProvider;
-
/** Field description */
private RepositoryServiceFactory servicefactory;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SearchResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SearchResource.java
index e636b60852..0b01dffeaa 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SearchResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SearchResource.java
@@ -37,7 +37,6 @@ package sonia.scm.api.rest.resources;
import com.google.common.base.Function;
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
@@ -54,7 +53,6 @@ import sonia.scm.search.SearchResults;
import sonia.scm.user.User;
import sonia.scm.user.UserListener;
import sonia.scm.user.UserManager;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -92,9 +90,8 @@ public class SearchResource implements UserListener, GroupListener
* @param cacheManager
*/
@Inject
- public SearchResource(Provider securityContextProvider,
- UserManager userManager, GroupManager groupManager,
- CacheManager cacheManager)
+ public SearchResource(UserManager userManager, GroupManager groupManager,
+ CacheManager cacheManager)
{
// create user searchhandler
@@ -103,8 +100,7 @@ public class SearchResource implements UserListener, GroupListener
Cache userCache =
cacheManager.getCache(String.class, SearchResults.class, CACHE_USER);
- this.userSearchHandler = new SearchHandler(securityContextProvider,
- userCache, userManager);
+ this.userSearchHandler = new SearchHandler(userCache, userManager);
// create group searchhandler
groupManager.addListener(this);
@@ -112,8 +108,8 @@ public class SearchResource implements UserListener, GroupListener
Cache groupCache =
cacheManager.getCache(String.class, SearchResults.class, CACHE_GROUP);
- this.groupSearchHandler = new SearchHandler(securityContextProvider,
- groupCache, groupManager);
+ this.groupSearchHandler = new SearchHandler(groupCache,
+ groupManager);
}
//~--- methods --------------------------------------------------------------
@@ -162,7 +158,7 @@ public class SearchResource implements UserListener, GroupListener
public SearchResults searchGroups(@QueryParam("query") String queryString)
{
return groupSearchHandler.search(queryString,
- new Function()
+ new Function()
{
@Override
public SearchResult apply(Group group)
@@ -198,7 +194,7 @@ public class SearchResource implements UserListener, GroupListener
public SearchResults searchUsers(@QueryParam("query") String queryString)
{
return userSearchHandler.search(queryString,
- new Function()
+ new Function()
{
@Override
public SearchResult apply(User user)
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SupportResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SupportResource.java
index 2472f81436..06f65c44d5 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SupportResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SupportResource.java
@@ -39,6 +39,9 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
import sonia.scm.SCMContextProvider;
@@ -47,10 +50,10 @@ import sonia.scm.config.ScmConfiguration;
import sonia.scm.plugin.PluginManager;
import sonia.scm.repository.RepositoryHandler;
import sonia.scm.repository.RepositoryManager;
+import sonia.scm.security.Role;
+import sonia.scm.security.ScmSecurityException;
import sonia.scm.store.StoreFactory;
-import sonia.scm.util.SecurityUtil;
import sonia.scm.util.SystemUtil;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -96,12 +99,10 @@ public class SupportResource
* @param repositoryManager
*/
@Inject
- public SupportResource(WebSecurityContext securityContext,
- SCMContextProvider context, ScmConfiguration configuration,
- PluginManager pluginManager, StoreFactory storeFactory,
- RepositoryManager repositoryManager)
+ public SupportResource(SCMContextProvider context,
+ ScmConfiguration configuration, PluginManager pluginManager,
+ StoreFactory storeFactory, RepositoryManager repositoryManager)
{
- this.securityContext = securityContext;
this.context = context;
this.configuration = configuration;
this.pluginManager = pluginManager;
@@ -123,7 +124,12 @@ public class SupportResource
@Produces(MediaType.TEXT_HTML)
public Viewable getSupport() throws IOException
{
- SecurityUtil.assertIsAdmin(securityContext);
+ Subject subject = SecurityUtils.getSubject();
+
+ if (!subject.hasRole(Role.ADMIN))
+ {
+ throw new ScmSecurityException("admin privileges required");
+ }
Map env = Maps.newHashMap();
@@ -445,9 +451,6 @@ public class SupportResource
/** Field description */
private RepositoryManager repositoryManager;
- /** Field description */
- private WebSecurityContext securityContext;
-
/** Field description */
private Class> storeFactoryClass;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserResource.java
index 62deb10607..ad264fd0a8 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserResource.java
@@ -36,20 +36,20 @@ package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+
import org.codehaus.enunciate.jaxrs.TypeHint;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
import sonia.scm.security.EncryptionHandler;
+import sonia.scm.security.Role;
import sonia.scm.user.User;
import sonia.scm.user.UserException;
import sonia.scm.user.UserManager;
import sonia.scm.util.AssertUtil;
-import sonia.scm.util.SecurityUtil;
import sonia.scm.util.Util;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -100,12 +100,10 @@ public class UserResource extends AbstractManagerResource
*/
@Inject
public UserResource(UserManager userManager,
- EncryptionHandler encryptionHandler,
- Provider securityContextProvider)
+ EncryptionHandler encryptionHandler)
{
super(userManager);
this.encryptionHandler = encryptionHandler;
- this.securityContextProvider = securityContextProvider;
}
//~--- methods --------------------------------------------------------------
@@ -179,7 +177,7 @@ public class UserResource extends AbstractManagerResource
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override
public Response update(@Context UriInfo uriInfo,
- @PathParam("id") String name, User user)
+ @PathParam("id") String name, User user)
{
return super.update(uriInfo, name, user);
}
@@ -212,7 +210,7 @@ public class UserResource extends AbstractManagerResource
{
Response response = null;
- if (SecurityUtil.isAdmin(securityContextProvider))
+ if (SecurityUtils.getSubject().hasRole(Role.ADMIN))
{
response = super.get(request, id);
}
@@ -250,7 +248,7 @@ public class UserResource extends AbstractManagerResource
public Response getAll(@Context Request request, @DefaultValue("0")
@QueryParam("start") int start, @DefaultValue("-1")
@QueryParam("limit") int limit, @QueryParam("sortby") String sortby,
- @DefaultValue("false")
+ @DefaultValue("false")
@QueryParam("desc") boolean desc)
{
return super.getAll(request, start, limit, sortby, desc);
@@ -268,7 +266,7 @@ public class UserResource extends AbstractManagerResource
*/
@Override
protected GenericEntity> createGenericEntity(
- Collection items)
+ Collection items)
{
return new GenericEntity>(items) {}
;
@@ -396,7 +394,4 @@ public class UserResource extends AbstractManagerResource
/** Field description */
private EncryptionHandler encryptionHandler;
-
- /** Field description */
- private Provider securityContextProvider;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/filter/AdminSecurityFilter.java b/scm-webapp/src/main/java/sonia/scm/filter/AdminSecurityFilter.java
index 272803d0b2..a458138910 100644
--- a/scm-webapp/src/main/java/sonia/scm/filter/AdminSecurityFilter.java
+++ b/scm-webapp/src/main/java/sonia/scm/filter/AdminSecurityFilter.java
@@ -36,11 +36,12 @@ package sonia.scm.filter;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
-import sonia.scm.util.SecurityUtil;
-import sonia.scm.web.security.WebSecurityContext;
+import org.apache.shiro.subject.Subject;
+
+import sonia.scm.config.ScmConfiguration;
+import sonia.scm.security.Role;
/**
*
@@ -54,13 +55,12 @@ public class AdminSecurityFilter extends SecurityFilter
* Constructs ...
*
*
- * @param securityContextProvider
+ * @param configuration
*/
@Inject
- public AdminSecurityFilter(
- Provider securityContextProvider)
+ public AdminSecurityFilter(ScmConfiguration configuration)
{
- super(securityContextProvider);
+ super(configuration);
}
//~--- get methods ----------------------------------------------------------
@@ -71,11 +71,13 @@ public class AdminSecurityFilter extends SecurityFilter
*
* @param securityContext
*
+ * @param subject
+ *
* @return
*/
@Override
- protected boolean hasPermission(WebSecurityContext securityContext)
+ protected boolean hasPermission(Subject subject)
{
- return SecurityUtil.isAdmin(securityContext);
+ return subject.hasRole(Role.ADMIN);
}
}
diff --git a/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java b/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java
index a276e5920e..ea3deec0e0 100644
--- a/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java
+++ b/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java
@@ -36,12 +36,16 @@ package sonia.scm.filter;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
+import sonia.scm.SCMContext;
+import sonia.scm.config.ScmConfiguration;
+import sonia.scm.user.User;
import sonia.scm.web.filter.HttpFilter;
import sonia.scm.web.filter.SecurityHttpServletRequestWrapper;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -69,12 +73,12 @@ public class SecurityFilter extends HttpFilter
* Constructs ...
*
*
- * @param securityContextProvider
+ * @param configuration
*/
@Inject
- public SecurityFilter(Provider securityContextProvider)
+ public SecurityFilter(ScmConfiguration configuration)
{
- this.securityContextProvider = securityContextProvider;
+ this.configuration = configuration;
}
//~--- methods --------------------------------------------------------------
@@ -92,40 +96,37 @@ public class SecurityFilter extends HttpFilter
*/
@Override
protected void doFilter(HttpServletRequest request,
- HttpServletResponse response, FilterChain chain)
- throws IOException, ServletException
+ HttpServletResponse response, FilterChain chain)
+ throws IOException, ServletException
{
- WebSecurityContext securityContext = securityContextProvider.get();
+ Subject subject = SecurityUtils.getSubject();
- if (securityContext != null)
+ String uri =
+ request.getRequestURI().substring(request.getContextPath().length());
+
+ if (!uri.startsWith(URL_AUTHENTICATION))
{
- String uri =
- request.getRequestURI().substring(request.getContextPath().length());
-
- if (!uri.startsWith(URL_AUTHENTICATION))
+ if (hasPermission(subject))
{
- if (hasPermission(securityContext))
- {
- chain.doFilter(new SecurityHttpServletRequestWrapper(request,
- securityContext.getUser()), response);
- }
- else if (securityContext.isAuthenticated())
- {
- response.sendError(HttpServletResponse.SC_FORBIDDEN);
- }
- else
- {
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
- }
+ chain.doFilter(new SecurityHttpServletRequestWrapper(request,
+ getUser(subject)), response);
+ }
+ else if (subject.isAuthenticated())
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ }
+ else if (configuration.isAnonymousAccessEnabled())
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
else
{
- chain.doFilter(request, response);
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
else
{
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ chain.doFilter(request, response);
}
}
@@ -135,17 +136,42 @@ public class SecurityFilter extends HttpFilter
* Method description
*
*
- * @param securityContext
+ * @param subject
*
* @return
*/
- protected boolean hasPermission(WebSecurityContext securityContext)
+ protected boolean hasPermission(Subject subject)
{
- return securityContext.isAuthenticated();
+ return ((configuration != null)
+ && configuration.isAnonymousAccessEnabled()) || subject.isAuthenticated();
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param subject
+ *
+ * @return
+ */
+ private User getUser(Subject subject)
+ {
+ User user = null;
+
+ if (subject.isAuthenticated())
+ {
+ user = subject.getPrincipals().oneByType(User.class);
+ }
+ else
+ {
+ user = SCMContext.ANONYMOUS;
+ }
+
+ return user;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
- private Provider securityContextProvider;
+ private ScmConfiguration configuration;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java
index 50e0fe90a9..9cf0f39af2 100644
--- a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java
+++ b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java
@@ -47,7 +47,6 @@ import sonia.scm.SCMContextProvider;
import sonia.scm.TransformFilter;
import sonia.scm.search.SearchRequest;
import sonia.scm.search.SearchUtil;
-import sonia.scm.security.SecurityContext;
import sonia.scm.util.CollectionAppender;
import sonia.scm.util.SecurityUtil;
import sonia.scm.util.Util;
@@ -87,11 +86,9 @@ public class DefaultGroupManager extends AbstractGroupManager
* @param groupListenerProvider
*/
@Inject
- public DefaultGroupManager(Provider securityContextProvider,
- GroupDAO groupDAO,
+ public DefaultGroupManager(GroupDAO groupDAO,
Provider> groupListenerProvider)
{
- this.securityContextProvider = securityContextProvider;
this.groupDAO = groupDAO;
this.groupListenerProvider = groupListenerProvider;
}
@@ -136,7 +133,7 @@ public class DefaultGroupManager extends AbstractGroupManager
group.getType());
}
- SecurityUtil.assertIsAdmin(securityContextProvider);
+ SecurityUtil.assertIsAdmin();
if (groupDAO.contains(group.getName()))
{
@@ -167,7 +164,7 @@ public class DefaultGroupManager extends AbstractGroupManager
group.getType());
}
- SecurityUtil.assertIsAdmin(securityContextProvider);
+ SecurityUtil.assertIsAdmin();
String name = group.getName();
@@ -218,7 +215,7 @@ public class DefaultGroupManager extends AbstractGroupManager
group.getType());
}
- SecurityUtil.assertIsAdmin(securityContextProvider);
+ SecurityUtil.assertIsAdmin();
String name = group.getName();
@@ -253,7 +250,7 @@ public class DefaultGroupManager extends AbstractGroupManager
group.getType());
}
- SecurityUtil.assertIsAdmin(securityContextProvider);
+ SecurityUtil.assertIsAdmin();
Group fresh = groupDAO.get(group.getName());
@@ -346,7 +343,7 @@ public class DefaultGroupManager extends AbstractGroupManager
@Override
public Collection getAll(Comparator comparator)
{
- SecurityUtil.assertIsAdmin(securityContextProvider);
+ SecurityUtil.assertIsAdmin();
List groups = new ArrayList();
@@ -378,7 +375,7 @@ public class DefaultGroupManager extends AbstractGroupManager
public Collection getAll(Comparator comparator, int start,
int limit)
{
- SecurityUtil.assertIsAdmin(securityContextProvider);
+ SecurityUtil.assertIsAdmin();
return Util.createSubCollection(groupDAO.getAll(), comparator,
new CollectionAppender()
@@ -449,7 +446,4 @@ public class DefaultGroupManager extends AbstractGroupManager
/** Field description */
private Provider> groupListenerProvider;
-
- /** Field description */
- private Provider securityContextProvider;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java
index 35ee52c115..5a2d2442d1 100644
--- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java
@@ -53,7 +53,6 @@ import sonia.scm.cache.CacheManager;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.io.ZipUnArchiver;
import sonia.scm.net.HttpClient;
-import sonia.scm.security.SecurityContext;
import sonia.scm.util.AssertUtil;
import sonia.scm.util.IOUtil;
import sonia.scm.util.SecurityUtil;
@@ -123,12 +122,10 @@ public class DefaultPluginManager
*/
@Inject
public DefaultPluginManager(SCMContextProvider context,
- Provider securityContextProvicer,
ScmConfiguration configuration, PluginLoader pluginLoader,
CacheManager cacheManager, Provider clientProvider)
{
this.context = context;
- this.securityContextProvicer = securityContextProvicer;
this.configuration = configuration;
this.cache = cacheManager.getCache(String.class, PluginCenter.class,
CACHE_NAME);
@@ -196,7 +193,7 @@ public class DefaultPluginManager
@Override
public void install(String id)
{
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
PluginCenter center = getPluginCenter();
@@ -230,7 +227,7 @@ public class DefaultPluginManager
@Override
public void installPackage(InputStream packageStream) throws IOException
{
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
File tempDirectory = Files.createTempDir();
@@ -276,7 +273,7 @@ public class DefaultPluginManager
@Override
public void uninstall(String id)
{
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
Plugin plugin = installedPlugins.get(id);
@@ -320,7 +317,7 @@ public class DefaultPluginManager
@Override
public void update(String id)
{
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
String[] idParts = id.split(":");
String groupId = idParts[0];
@@ -364,7 +361,7 @@ public class DefaultPluginManager
@Override
public PluginInformation get(String id)
{
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
PluginInformation result = null;
@@ -393,7 +390,7 @@ public class DefaultPluginManager
public Set get(PluginFilter filter)
{
AssertUtil.assertIsNotNull(filter);
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
Set infoSet = new HashSet();
@@ -412,7 +409,7 @@ public class DefaultPluginManager
@Override
public Collection getAll()
{
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
Set infoSet = getInstalled();
@@ -430,7 +427,7 @@ public class DefaultPluginManager
@Override
public Collection getAvailable()
{
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
Set availablePlugins = new HashSet();
Set centerPlugins = getPluginCenter().getPlugins();
@@ -455,7 +452,7 @@ public class DefaultPluginManager
@Override
public Set getAvailableUpdates()
{
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
return get(FILTER_UPDATES);
}
@@ -469,7 +466,7 @@ public class DefaultPluginManager
@Override
public Set getInstalled()
{
- SecurityUtil.assertIsAdmin(securityContextProvicer);
+ SecurityUtil.assertIsAdmin();
Set infoSet = new LinkedHashSet();
@@ -765,9 +762,6 @@ public class DefaultPluginManager
/** Field description */
private AetherPluginHandler pluginHandler;
- /** Field description */
- private Provider securityContextProvicer;
-
/** Field description */
private Unmarshaller unmarshaller;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java
index ffa9123050..54b015067c 100644
--- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java
+++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java
@@ -36,10 +36,15 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.concurrent.SubjectAwareExecutorService;
+import org.apache.shiro.subject.Subject;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,15 +60,12 @@ import sonia.scm.util.AssertUtil;
import sonia.scm.util.CollectionAppender;
import sonia.scm.util.HttpUtil;
import sonia.scm.util.IOUtil;
-import sonia.scm.util.SecurityUtil;
import sonia.scm.util.Util;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -94,10 +96,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
/**
* Constructs ...
*
- *
- *
- *
- *
* @param configuration
* @param contextProvider
* @param keyGenerator
@@ -110,18 +108,18 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
@Inject
public DefaultRepositoryManager(ScmConfiguration configuration,
SCMContextProvider contextProvider, KeyGenerator keyGenerator,
- Provider securityContextProvider,
RepositoryDAO repositoryDAO, Set handlerSet,
Provider> repositoryListenersProvider,
Provider> repositoryHooksProvider)
{
this.configuration = configuration;
- this.securityContextProvider = securityContextProvider;
this.keyGenerator = keyGenerator;
this.repositoryDAO = repositoryDAO;
this.repositoryListenersProvider = repositoryListenersProvider;
this.repositoryHooksProvider = repositoryHooksProvider;
- this.executorService = Executors.newCachedThreadPool();
+
+ this.executorService =
+ new SubjectAwareExecutorService(Executors.newCachedThreadPool());
handlerMap = new HashMap();
types = new HashSet();
@@ -169,7 +167,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
repository.getType());
}
- SecurityUtil.assertIsAdmin(securityContextProvider);
+ assertIsAdmin();
AssertUtil.assertIsValid(repository);
if (repositoryDAO.contains(repository))
@@ -475,7 +473,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
@Override
public Collection getAll(Comparator comparator)
{
- List repositories = new ArrayList();
+ List repositories = Lists.newArrayList();
for (Repository repository : repositoryDAO.getAll())
{
@@ -603,7 +601,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
@Override
public Collection getConfiguredTypes()
{
- List validTypes = new ArrayList();
+ List validTypes = Lists.newArrayList();
for (RepositoryHandler handler : handlerMap.values())
{
@@ -867,25 +865,44 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
/**
* Method description
*
+ */
+ private void assertIsAdmin()
+ {
+ if (!SecurityUtils.getSubject().hasRole("admin"))
+ {
+ throw new ScmSecurityException("admin role is required");
+ }
+ }
+
+ /**
+ * TODO use {@link Subject#checkPermission(org.apache.shiro.authz.Permission)}
+ * in version 2.x.
+ *
*
* @param repository
*/
private void assertIsOwner(Repository repository)
{
- PermissionUtil.assertPermission(repository, securityContextProvider,
- PermissionType.OWNER);
+ if (!isPermitted(repository, PermissionType.OWNER))
+ {
+ throw new ScmSecurityException(
+ "owner permission is required, access denied");
+ }
}
/**
- * Method description
- *
+ * TODO use {@link Subject#checkPermission(org.apache.shiro.authz.Permission)}
+ * in version 2.x.
*
* @param repository
*/
private void assertIsReader(Repository repository)
{
- PermissionUtil.assertPermission(repository, securityContextProvider,
- PermissionType.READ);
+ if (!isReader(repository))
+ {
+ throw new ScmSecurityException(
+ "reader permission is required, access denied");
+ }
}
//~--- get methods ----------------------------------------------------------
@@ -944,6 +961,20 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
return result;
}
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ * @param type
+ *
+ * @return
+ */
+ private boolean isPermitted(Repository repository, PermissionType type)
+ {
+ return PermissionUtil.hasPermission(configuration, repository, type);
+ }
+
/**
* Method description
*
@@ -954,8 +985,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
*/
private boolean isReader(Repository repository)
{
- return PermissionUtil.hasPermission(repository, securityContextProvider,
- PermissionType.READ);
+ return isPermitted(repository, PermissionType.READ);
}
//~--- fields ---------------------------------------------------------------
@@ -981,9 +1011,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
/** Field description */
private Provider> repositoryListenersProvider;
- /** Field description */
- private Provider securityContextProvider;
-
/** Field description */
private Set types;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/search/SearchHandler.java b/scm-webapp/src/main/java/sonia/scm/search/SearchHandler.java
index 4ecbbf33e0..b06c11b69f 100644
--- a/scm-webapp/src/main/java/sonia/scm/search/SearchHandler.java
+++ b/scm-webapp/src/main/java/sonia/scm/search/SearchHandler.java
@@ -37,15 +37,16 @@ package sonia.scm.search;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
-import com.google.inject.Provider;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.cache.Cache;
-import sonia.scm.util.SecurityUtil;
+import sonia.scm.security.ScmSecurityException;
import sonia.scm.util.Util;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -77,11 +78,10 @@ public class SearchHandler
* @param cache
* @param searchable
*/
- public SearchHandler(Provider securityContextProvider,
- Cache cache,
- Searchable searchable)
+ public SearchHandler(Cache cache,
+ Searchable searchable)
{
- this.securityContextProvider = securityContextProvider;
+
this.cache = cache;
this.searchable = searchable;
}
@@ -107,9 +107,14 @@ public class SearchHandler
* @return
*/
public SearchResults search(String queryString,
- Function function)
+ Function function)
{
- SecurityUtil.assertIsNotAnonymous(securityContextProvider);
+ Subject subject = SecurityUtils.getSubject();
+
+ if (!subject.isAuthenticated())
+ {
+ throw new ScmSecurityException("Authentication is required");
+ }
if (Util.isEmpty(queryString))
{
@@ -202,9 +207,6 @@ public class SearchHandler
/** Field description */
protected Searchable searchable;
- /** Field description */
- protected Provider securityContextProvider;
-
/** Field description */
private int maxResults = 5;
diff --git a/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionResolver.java b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionResolver.java
new file mode 100644
index 0000000000..4d4417aaa1
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/security/RepositoryPermissionResolver.java
@@ -0,0 +1,149 @@
+/**
+ * Copyright (c) 2010, 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.common.base.Splitter;
+
+import org.apache.shiro.authz.permission.PermissionResolver;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import sonia.scm.repository.PermissionType;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.util.Iterator;
+import java.util.Locale;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class RepositoryPermissionResolver implements PermissionResolver
+{
+
+ /** Field description */
+ private static final String TYPE_REPOSITORY = "repository";
+
+ /**
+ * the logger for RepositoryPermissionResolver
+ */
+ private static final Logger logger =
+ LoggerFactory.getLogger(RepositoryPermissionResolver.class);
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param permissionString
+ *
+ * @return
+ */
+ @Override
+ public RepositoryPermission resolvePermission(String permissionString)
+ {
+ RepositoryPermission permission = null;
+ Iterator permissionIt =
+ Splitter.on(':').omitEmptyStrings().trimResults().split(
+ permissionString).iterator();
+
+ if (permissionIt.hasNext())
+ {
+ String type = permissionIt.next();
+
+ if (type.equals(TYPE_REPOSITORY))
+ {
+ permission = createRepositoryPermission(permissionIt);
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("permission '{}' is not a repository permission",
+ permissionString);
+ }
+ }
+
+ return permission;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param permissionIt
+ *
+ * @return
+ */
+ private RepositoryPermission createRepositoryPermission(
+ Iterator permissionIt)
+ {
+ RepositoryPermission permission = null;
+
+ if (permissionIt.hasNext())
+ {
+ String repositoryId = permissionIt.next();
+
+ if (permissionIt.hasNext())
+ {
+ try
+ {
+ String typeString = permissionIt.next();
+
+ typeString = typeString.trim().toUpperCase(Locale.ENGLISH);
+
+ PermissionType type = PermissionType.valueOf(typeString);
+
+ permission = new RepositoryPermission(repositoryId, type);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ logger.warn("type is not a valid permission type", ex);
+ }
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("permission type is missing");
+ }
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("repository id and permission type is missing");
+ }
+
+ return permission;
+ }
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/security/ScmRealm.java b/scm-webapp/src/main/java/sonia/scm/security/ScmRealm.java
new file mode 100644
index 0000000000..80e9b694b3
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/security/ScmRealm.java
@@ -0,0 +1,777 @@
+/**
+ * Copyright (c) 2010, 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+import org.apache.shiro.authc.AccountException;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.DisabledAccountException;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authc.UnknownAccountException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authc.pam.UnsupportedTokenException;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+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.cache.Cache;
+import sonia.scm.cache.CacheManager;
+import sonia.scm.config.ScmConfiguration;
+import sonia.scm.group.Group;
+import sonia.scm.group.GroupManager;
+import sonia.scm.group.GroupNames;
+import sonia.scm.repository.Permission;
+import sonia.scm.repository.PermissionType;
+import sonia.scm.repository.Repository;
+import sonia.scm.repository.RepositoryDAO;
+import sonia.scm.repository.RepositoryListener;
+import sonia.scm.repository.RepositoryManager;
+import sonia.scm.user.User;
+import sonia.scm.user.UserDAO;
+import sonia.scm.user.UserEventHack;
+import sonia.scm.user.UserException;
+import sonia.scm.user.UserListener;
+import sonia.scm.user.UserManager;
+import sonia.scm.util.Util;
+import sonia.scm.web.security.AuthenticationManager;
+import sonia.scm.web.security.AuthenticationResult;
+import sonia.scm.web.security.AuthenticationState;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Singleton
+public class ScmRealm extends AuthorizingRealm
+ implements RepositoryListener, UserListener
+{
+
+ /** Field description */
+ public static final String NAME = "scm";
+
+ /** Field description */
+ private static final String CACHE_NAME = "sonia.cache.authorizing";
+
+ /** Field description */
+ private static final String SCM_CREDENTIALS = "SCM_CREDENTIALS";
+
+ /**
+ * the logger for ScmRealm
+ */
+ private static final Logger logger = LoggerFactory.getLogger(ScmRealm.class);
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ *
+ * @param configuration
+ * @param cacheManager
+ * @param userManager
+ * @param groupManager
+ * @param repositoryManager
+ * @param repositoryDAO
+ * @param userDAO
+ * @param authenticator
+ * @param requestProvider
+ * @param responseProvider
+ */
+ @Inject
+ public ScmRealm(ScmConfiguration configuration, CacheManager cacheManager,
+ UserManager userManager, GroupManager groupManager,
+ RepositoryManager repositoryManager, RepositoryDAO repositoryDAO,
+ UserDAO userDAO, AuthenticationManager authenticator,
+ Provider requestProvider,
+ Provider responseProvider)
+ {
+ this.configuration = configuration;
+ this.userManager = userManager;
+ this.groupManager = groupManager;
+ this.repositoryDAO = repositoryDAO;
+ this.userDAO = userDAO;
+ this.authenticator = authenticator;
+ this.requestProvider = requestProvider;
+ this.responseProvider = responseProvider;
+
+ // init cache
+ this.cache = cacheManager.getCache(String.class, AuthorizationInfo.class,
+ CACHE_NAME);
+
+ // set token class
+ setAuthenticationTokenClass(UsernamePasswordToken.class);
+
+ // use own custom caching
+ setCachingEnabled(false);
+ setAuthenticationCachingEnabled(false);
+ setAuthorizationCachingEnabled(false);
+
+ // set components
+ setPermissionResolver(new RepositoryPermissionResolver());
+
+ // add listeners for caching
+ userManager.addListener(this);
+ repositoryManager.addListener(this);
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param repository
+ * @param event
+ */
+ @Override
+ public void onEvent(Repository repository, HandlerEvent event)
+ {
+ if (event.isPost())
+ {
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("clear cache, because repository {} has changed",
+ repository.getName());
+ }
+
+ cache.clear();
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param user
+ * @param event
+ */
+ @Override
+ public void onEvent(User user, HandlerEvent event)
+ {
+ if (event.isPost())
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(
+ "clear cache of user {}, because user properties have changed",
+ user.getName());
+ }
+
+ cache.remove(user.getId());
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param token
+ *
+ * @param authToken
+ *
+ * @return
+ *
+ * @throws AuthenticationException
+ */
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(
+ AuthenticationToken authToken)
+ throws AuthenticationException
+ {
+ if (!(authToken instanceof UsernamePasswordToken))
+ {
+ throw new UnsupportedTokenException("ScmAuthenticationToken is required");
+ }
+
+ UsernamePasswordToken token = (UsernamePasswordToken) authToken;
+
+ AuthenticationInfo info = null;
+ AuthenticationResult result =
+ authenticator.authenticate(requestProvider.get(), responseProvider.get(),
+ token.getUsername(), new String(token.getPassword()));
+
+ if ((result != null) && (AuthenticationState.SUCCESS == result.getState()))
+ {
+ info = createAuthenticationInfo(token, result);
+ }
+ else if ((result != null)
+ && (AuthenticationState.NOT_FOUND == result.getState()))
+ {
+ throw new UnknownAccountException(
+ "unknown account ".concat(token.getUsername()));
+ }
+ else
+ {
+ throw new AccountException("authentication failed");
+ }
+
+ return info;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param principals
+ *
+ * @return
+ */
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(
+ PrincipalCollection principals)
+ {
+ User user = principals.oneByType(User.class);
+
+ AuthorizationInfo info = cache.get(user.getId());
+
+ if (info == null)
+ {
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("collect AuthorizationInfo for user {}", user.getName());
+ }
+
+ GroupNames groups = principals.oneByType(GroupNames.class);
+
+ info = createAuthorizationInfo(user, groups);
+ cache.put(user.getId(), info);
+ }
+ else if (logger.isTraceEnabled())
+ {
+ logger.trace("retrieve AuthorizationInfo for user {} from cache",
+ user.getName());
+ }
+
+ return info;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ * @param password
+ * @param ar
+ *
+ * @return
+ */
+ 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 (Exception ex)
+ {
+ logger.error("authentication failed", ex);
+
+ throw new AuthenticationException("authentication failed", ex);
+ }
+
+ return groupSet;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param user
+ * @param dbUser
+ */
+ 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);
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param user
+ * @param dbUser
+ *
+ * @throws IOException
+ * @throws UserException
+ */
+ 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))
+ {
+ userManager.modify(dbUser);
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param user
+ * @param groupSet
+ */
+ 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());
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param user
+ * @param groups
+ *
+ * @return
+ */
+ private List collectRepositoryPermissions(
+ User user, GroupNames groups)
+ {
+ List permissions = Lists.newArrayList();
+
+ for (Repository repository : repositoryDAO.getAll())
+ {
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("collect permissions for repository {} and user {}",
+ repository.getName(), user.getName());
+ }
+
+ collectRepositoryPermissions(permissions, repository, user, groups);
+ }
+
+ return permissions;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param permissions
+ * @param repository
+ * @param user
+ * @param groups
+ */
+ private void collectRepositoryPermissions(
+ List permissions, Repository repository,
+ User user, GroupNames groups)
+ {
+ List repositoryPermissions = repository.getPermissions();
+
+ if (Util.isNotEmpty(repositoryPermissions))
+ {
+
+ for (Permission permission : repositoryPermissions)
+ {
+ if (isUserPermission(user, groups, permission))
+ {
+ RepositoryPermission rp = new RepositoryPermission(repository,
+ permission.getType());
+
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("add repository permission {} for user {}", rp,
+ user.getName());
+ }
+
+ permissions.add(rp);
+ }
+ }
+ }
+ else if (logger.isTraceEnabled())
+ {
+ logger.trace("repository {} has not permission entries",
+ repository.getName());
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param token
+ * @param result
+ *
+ * @return
+ */
+ private AuthenticationInfo createAuthenticationInfo(
+ UsernamePasswordToken token, AuthenticationResult result)
+ {
+ User user = result.getUser();
+ Collection groups = authenticate(requestProvider.get(),
+ new String(token.getPassword()), result);
+
+ SimplePrincipalCollection collection = new SimplePrincipalCollection();
+
+ /*
+ * the first (primary) principal should be a unique identifier
+ */
+ collection.add(user.getId(), NAME);
+ collection.add(user, NAME);
+ collection.add(new GroupNames(groups), NAME);
+
+ return new SimpleAuthenticationInfo(collection, token.getPassword());
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param user
+ * @param groups
+ *
+ * @return
+ */
+ private AuthorizationInfo createAuthorizationInfo(User user,
+ GroupNames groups)
+ {
+ Set roles = Sets.newHashSet();
+ List permissions = null;
+
+ roles.add(Role.USER);
+
+ if (user.isAdmin())
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("grant admin role for user {}", user.getName());
+ }
+
+ roles.add(Role.ADMIN);
+ permissions = Lists.newArrayList();
+ permissions.add(new RepositoryPermission(RepositoryPermission.WILDCARD,
+ PermissionType.OWNER));
+ }
+ else
+ {
+ permissions = collectRepositoryPermissions(user, groups);
+ }
+
+ SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
+
+ info.addObjectPermissions(permissions);
+
+ return info;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param ar
+ *
+ * @return
+ */
+ private Set createGroupSet(AuthenticationResult ar)
+ {
+ Set groupSet = Sets.newHashSet();
+
+ // load external groups
+ Collection extGroups = ar.getGroups();
+
+ if (extGroups != null)
+ {
+ groupSet.addAll(extGroups);
+ }
+
+ // load internal groups
+ loadGroups(ar.getUser(), groupSet);
+
+ return groupSet;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ *
+ * @param user
+ * @param 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());
+ }
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param user
+ * @param groups
+ */
+ 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());
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ *
+ *
+ * @param user
+ * @param groups
+ * @return
+ */
+ 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;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param user
+ * @param groups
+ * @param perm
+ *
+ * @return
+ */
+ private boolean isUserPermission(User user, GroupNames groups,
+ Permission perm)
+ {
+ //J-
+ return (perm.isGroupPermission() && groups.contains(perm.getName()))
+ || ((!perm.isGroupPermission()) && user.getName().equals(perm.getName()));
+ //J+
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private AuthenticationManager authenticator;
+
+ /** Field description */
+ private Cache cache;
+
+ /** Field description */
+ private ScmConfiguration configuration;
+
+ /** Field description */
+ private GroupManager groupManager;
+
+ /** Field description */
+ private RepositoryDAO repositoryDAO;
+
+ /** Field description */
+ private Provider requestProvider;
+
+ /** Field description */
+ private Provider responseProvider;
+
+ /** Field description */
+ private UserDAO userDAO;
+
+ /** Field description */
+ private UserManager userManager;
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/template/MustacheTemplateNotFoundException.java b/scm-webapp/src/main/java/sonia/scm/template/MustacheTemplateNotFoundException.java
index 0f9038d73b..f9c0e59e00 100644
--- a/scm-webapp/src/main/java/sonia/scm/template/MustacheTemplateNotFoundException.java
+++ b/scm-webapp/src/main/java/sonia/scm/template/MustacheTemplateNotFoundException.java
@@ -1,34 +1,35 @@
/**
- * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ * Copyright (c) 2010, 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 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.
+ * 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.template;
/**
diff --git a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java
index 2b5a89357d..807da0cf62 100644
--- a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java
+++ b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java
@@ -39,6 +39,9 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -47,13 +50,13 @@ import sonia.scm.SCMContextProvider;
import sonia.scm.TransformFilter;
import sonia.scm.search.SearchRequest;
import sonia.scm.search.SearchUtil;
+import sonia.scm.security.Role;
import sonia.scm.security.ScmSecurityException;
import sonia.scm.util.AssertUtil;
import sonia.scm.util.CollectionAppender;
import sonia.scm.util.IOUtil;
import sonia.scm.util.SecurityUtil;
import sonia.scm.util.Util;
-import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
@@ -104,11 +107,9 @@ public class DefaultUserManager extends AbstractUserManager
* @param userListenerProvider
*/
@Inject
- public DefaultUserManager(
- Provider scurityContextProvider, UserDAO userDAO,
- Provider> userListenerProvider)
+ public DefaultUserManager(UserDAO userDAO,
+ Provider> userListenerProvider)
{
- this.scurityContextProvider = scurityContextProvider;
this.userDAO = userDAO;
this.userListenerProvider = userListenerProvider;
}
@@ -166,9 +167,14 @@ public class DefaultUserManager extends AbstractUserManager
logger.info("create user {} of type {}", user.getName(), user.getType());
}
- User currentUser = SecurityUtil.getCurrentUser(scurityContextProvider);
+ Subject subject = SecurityUtils.getSubject();
- if (!user.equals(currentUser) &&!currentUser.isAdmin())
+ if (!subject.isAuthenticated())
+ {
+ throw new ScmSecurityException("user is not authenticated");
+ }
+
+ if (!subject.hasRole(Role.ADMIN))
{
throw new ScmSecurityException("admin account is required");
}
@@ -202,7 +208,7 @@ public class DefaultUserManager extends AbstractUserManager
logger.info("delete user {} of type {}", user.getName(), user.getType());
}
- SecurityUtil.assertIsAdmin(scurityContextProvider);
+ SecurityUtil.assertIsAdmin();
String name = user.getName();
@@ -259,9 +265,17 @@ public class DefaultUserManager extends AbstractUserManager
logger.info("modify user {} of type {}", user.getName(), user.getType());
}
- User currentUser = SecurityUtil.getCurrentUser(scurityContextProvider);
+ Subject subject = SecurityUtils.getSubject();
- if (!user.getName().equals(currentUser.getName()) &&!currentUser.isAdmin())
+ if (!subject.isAuthenticated())
+ {
+ throw new ScmSecurityException("user is not authenticated");
+ }
+
+ User currentUser = subject.getPrincipals().oneByType(User.class);
+
+ if (!user.getName().equals(currentUser.getName())
+ &&!subject.hasRole(Role.ADMIN))
{
throw new ScmSecurityException("admin account is required");
}
@@ -299,7 +313,7 @@ public class DefaultUserManager extends AbstractUserManager
logger.info("refresh user {} of type {}", user.getName(), user.getType());
}
- SecurityUtil.assertIsAdmin(scurityContextProvider);
+ SecurityUtil.assertIsAdmin();
User fresh = userDAO.get(user.getName());
@@ -328,7 +342,7 @@ public class DefaultUserManager extends AbstractUserManager
}
return SearchUtil.search(searchRequest, userDAO.getAll(),
- new TransformFilter()
+ new TransformFilter()
{
@Override
public User accept(User user)
@@ -336,7 +350,7 @@ public class DefaultUserManager extends AbstractUserManager
User result = null;
if (SearchUtil.matchesOne(searchRequest, user.getName(),
- user.getDisplayName(), user.getMail()))
+ user.getDisplayName(), user.getMail()))
{
result = user.clone();
}
@@ -394,7 +408,7 @@ public class DefaultUserManager extends AbstractUserManager
@Override
public Collection getAll(Comparator comparator)
{
- SecurityUtil.assertIsAdmin(scurityContextProvider);
+ SecurityUtil.assertIsAdmin();
List users = new ArrayList();
@@ -424,12 +438,12 @@ public class DefaultUserManager extends AbstractUserManager
*/
@Override
public Collection getAll(Comparator comaparator, int start,
- int limit)
+ int limit)
{
- SecurityUtil.assertIsAdmin(scurityContextProvider);
+ SecurityUtil.assertIsAdmin();
return Util.createSubCollection(userDAO.getAll(), comaparator,
- new CollectionAppender()
+ new CollectionAppender()
{
@Override
public void append(Collection collection, User item)
@@ -525,15 +539,12 @@ public class DefaultUserManager extends AbstractUserManager
}
catch (JAXBException ex)
{
- logger.error(ex.getMessage(), ex);
+ logger.error("could not create default accounts", ex);
}
}
//~--- fields ---------------------------------------------------------------
- /** Field description */
- private Provider scurityContextProvider;
-
/** Field description */
private UserDAO userDAO;
diff --git a/scm-webapp/src/main/java/sonia/scm/user/UserEventHack.java b/scm-webapp/src/main/java/sonia/scm/user/UserEventHack.java
new file mode 100644
index 0000000000..13d5f1f42b
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/user/UserEventHack.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2010, 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.user;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import sonia.scm.HandlerEvent;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class UserEventHack
+{
+
+ /**
+ * the logger for UserEventHack
+ */
+ private static final Logger logger =
+ LoggerFactory.getLogger(UserEventHack.class);
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param userManager
+ * @param user
+ * @param event
+ */
+ public static void fireEvent(UserManager userManager, User user,
+ HandlerEvent event)
+ {
+ if (userManager instanceof AbstractUserManager)
+ {
+ ((AbstractUserManager) userManager).fireEvent(user, event);
+ }
+ else if (logger.isWarnEnabled())
+ {
+ logger.warn("user manager is not an instance of AbstractUserManager");
+ }
+ }
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/ApiBasicAuthenticationFilter.java b/scm-webapp/src/main/java/sonia/scm/web/security/ApiBasicAuthenticationFilter.java
index c0e9718ae7..12e168b8ea 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/security/ApiBasicAuthenticationFilter.java
+++ b/scm-webapp/src/main/java/sonia/scm/web/security/ApiBasicAuthenticationFilter.java
@@ -36,9 +36,9 @@ package sonia.scm.web.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
+import sonia.scm.config.ScmConfiguration;
import sonia.scm.web.filter.BasicAuthenticationFilter;
//~--- JDK imports ------------------------------------------------------------
@@ -73,13 +73,12 @@ public class ApiBasicAuthenticationFilter extends BasicAuthenticationFilter
* Constructs ...
*
*
- * @param securityContextProvider
+ * @param configuration
*/
@Inject
- public ApiBasicAuthenticationFilter(
- Provider securityContextProvider)
+ public ApiBasicAuthenticationFilter(ScmConfiguration configuration)
{
- super(securityContextProvider);
+ super(configuration);
}
//~--- methods --------------------------------------------------------------
@@ -97,14 +96,14 @@ public class ApiBasicAuthenticationFilter extends BasicAuthenticationFilter
*/
@Override
protected void doFilter(HttpServletRequest request,
- HttpServletResponse response, FilterChain chain)
- throws IOException, ServletException
+ HttpServletResponse response, FilterChain chain)
+ throws IOException, ServletException
{
// skip filter on authentication resource
if (request.getRequestURI().contains(URI_LOGIN)
- || request.getRequestURI().contains(URI_STATE)
- || request.getRequestURI().contains(URI_LOGOUT))
+ || request.getRequestURI().contains(URI_STATE)
+ || request.getRequestURI().contains(URI_LOGOUT))
{
chain.doFilter(request, response);
}
@@ -127,9 +126,8 @@ public class ApiBasicAuthenticationFilter extends BasicAuthenticationFilter
*/
@Override
protected void handleUnauthorized(HttpServletRequest request,
- HttpServletResponse response,
- FilterChain chain)
- throws IOException, ServletException
+ HttpServletResponse response, FilterChain chain)
+ throws IOException, ServletException
{
chain.doFilter(request, response);
}
diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java
index cf1c78f97c..1cd5d645cd 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java
+++ b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java
@@ -35,30 +35,26 @@ package sonia.scm.web.security;
//~--- non-JDK imports --------------------------------------------------------
-import com.google.common.collect.Sets;
import com.google.inject.Inject;
-import com.google.inject.servlet.SessionScoped;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.config.ScmConfiguration;
-import sonia.scm.group.Group;
-import sonia.scm.group.GroupManager;
-import sonia.scm.security.CipherUtil;
+import sonia.scm.group.GroupNames;
+import sonia.scm.security.Tokens;
import sonia.scm.user.User;
-import sonia.scm.user.UserException;
import sonia.scm.user.UserManager;
-import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
-import java.io.IOException;
-
import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
+import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -68,7 +64,6 @@ import javax.servlet.http.HttpSession;
*
* @author Sebastian Sdorra
*/
-@SessionScoped
public class BasicSecurityContext implements WebSecurityContext
{
@@ -88,21 +83,14 @@ public class BasicSecurityContext implements WebSecurityContext
* Constructs ...
*
*
- *
* @param configuration
- * @param authenticator
- * @param groupManager
* @param userManager
*/
@Inject
public BasicSecurityContext(ScmConfiguration configuration,
- AuthenticationManager authenticator,
- GroupManager groupManager,
- UserManager userManager)
+ UserManager userManager)
{
this.configuration = configuration;
- this.authenticator = authenticator;
- this.groupManager = groupManager;
this.userManager = userManager;
}
@@ -121,22 +109,27 @@ public class BasicSecurityContext implements WebSecurityContext
*/
@Override
public User authenticate(HttpServletRequest request,
- HttpServletResponse response, String username,
- String password)
+ HttpServletResponse response, String username, String password)
{
- if ( logger.isTraceEnabled() ){
- logger.trace("start authentication for user {}", username);
- }
- AuthenticationResult ar = authenticator.authenticate(request, response,
- username, password);
+ User user = null;
- if ( logger.isTraceEnabled() ){
- logger.trace("authentication ends with {}", ar);
- }
-
- if ((ar != null) && (ar.getState() == AuthenticationState.SUCCESS))
+ try
{
- authenticate(request, password, ar);
+
+ Subject subject = SecurityUtils.getSubject();
+
+ subject.login(Tokens.createAuthenticationToken(request, username,
+ password));
+
+ user = subject.getPrincipals().oneByType(User.class);
+
+ }
+ catch (AuthenticationException ex)
+ {
+ if (logger.isWarnEnabled())
+ {
+ logger.warn("authentication failed", ex);
+ }
}
return user;
@@ -152,8 +145,7 @@ public class BasicSecurityContext implements WebSecurityContext
@Override
public void logout(HttpServletRequest request, HttpServletResponse response)
{
- user = null;
- groups = new HashSet();
+ SecurityUtils.getSubject().logout();
HttpSession session = request.getSession(false);
@@ -174,12 +166,20 @@ public class BasicSecurityContext implements WebSecurityContext
@Override
public Collection getGroups()
{
- if (groups == null)
+ GroupNames groups = getPrincipal(GroupNames.class);
+
+ Collection groupCollection = null;
+
+ if (groups != null)
{
- groups = new HashSet();
+ groupCollection = groups.getCollection();
+ }
+ else
+ {
+ groupCollection = Collections.EMPTY_LIST;
}
- return groups;
+ return groupCollection;
}
/**
@@ -191,6 +191,8 @@ public class BasicSecurityContext implements WebSecurityContext
@Override
public User getUser()
{
+ User user = getPrincipal(User.class);
+
if ((user == null) && configuration.isAnonymousAccessEnabled())
{
user = userManager.get(USER_ANONYMOUS);
@@ -211,276 +213,27 @@ public class BasicSecurityContext implements WebSecurityContext
return getUser() != null;
}
- //~--- methods --------------------------------------------------------------
-
/**
* Method description
*
*
- * @param request
- * @param password
- * @param ar
- */
- private void authenticate(HttpServletRequest request, String password,
- AuthenticationResult ar)
- {
- user = ar.getUser();
-
- try
- {
- Set groupSet = createGroupSet(ar);
-
- // check for admin user
- checkForAuthenticatedAdmin(user, groupSet);
-
- // store user
- User dbUser = userManager.get(user.getName());
-
- if (dbUser != null)
- {
- checkDBForAdmin(user, dbUser);
- checkDBForActive(user, dbUser);
- }
-
- // create new user
- else
- {
- userManager.create(user);
- }
-
- if (user.isActive())
- {
- groups = groupSet;
-
- if (logger.isDebugEnabled())
- {
- logGroups();
- }
-
- // 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
- {
- if (logger.isWarnEnabled())
- {
- logger.warn("user {} is deactivated", user.getName());
- }
-
- user = null;
- groups = null;
- }
- }
- catch (Exception ex)
- {
- user = null;
-
- if (groups != null)
- {
- groups.clear();
- }
-
- logger.error("authentication failed", ex);
- }
- }
-
- /**
- * Method description
- *
- *
- * @param user
- * @param dbUser
- */
- 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);
- }
- }
-
- /**
- * Method description
- *
- *
- * @param user
- * @param dbUser
- *
- * @throws IOException
- * @throws UserException
- */
- 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))
- {
- userManager.modify(dbUser);
- }
- }
-
- /**
- * Method description
- *
- *
- * @param user
- * @param groupSet
- */
- private void checkForAuthenticatedAdmin(User user, Set groupSet)
- {
- if (!user.isAdmin())
- {
- user.setAdmin(isAdmin(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());
- }
- }
-
- /**
- * Method description
- *
- *
- * @param ar
+ * @param clazz
+ * @param
*
* @return
*/
- private Set createGroupSet(AuthenticationResult ar)
+ private T getPrincipal(Class clazz)
{
- Set groupSet = Sets.newHashSet();
+ T result = null;
+ Subject subject = SecurityUtils.getSubject();
- // load external groups
- Collection extGroups = ar.getGroups();
-
- if (extGroups != null)
+ if (subject.isAuthenticated())
{
- groupSet.addAll(extGroups);
- }
+ PrincipalCollection pc = subject.getPrincipals();
- // load internal groups
- loadGroups(groupSet);
-
- return groupSet;
- }
-
- /**
- * Method description
- *
- *
- * @param groupSet
- */
- private void loadGroups(Set groupSet)
- {
- Collection groupCollection =
- groupManager.getGroupsForMember(user.getName());
-
- if (groupCollection != null)
- {
- for (Group group : groupCollection)
+ if (pc != null)
{
- groupSet.add(group.getName());
- }
- }
- }
-
- /**
- * Method description
- *
- */
- private void logGroups()
- {
- StringBuilder msg = new StringBuilder("user ");
-
- msg.append(user.getName());
-
- if (Util.isNotEmpty(groups))
- {
- msg.append(" is member of ");
-
- Iterator groupIt = groups.iterator();
-
- while (groupIt.hasNext())
- {
- msg.append(groupIt.next());
-
- if (groupIt.hasNext())
- {
- msg.append(", ");
- }
- }
- }
- else
- {
- msg.append(" is not a member of a group");
- }
-
- logger.debug(msg.toString());
- }
-
- //~--- get methods ----------------------------------------------------------
-
- /**
- * Method description
- *
- *
- *
- * @param groups
- * @return
- */
- private boolean isAdmin(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);
+ result = pc.oneByType(clazz);
}
}
@@ -489,21 +242,9 @@ public class BasicSecurityContext implements WebSecurityContext
//~--- fields ---------------------------------------------------------------
- /** Field description */
- private AuthenticationManager authenticator;
-
/** Field description */
private ScmConfiguration configuration;
- /** Field description */
- private GroupManager groupManager;
-
- /** Field description */
- private Set groups = new HashSet();
-
- /** Field description */
- private User user;
-
/** Field description */
private UserManager userManager;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java b/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java
index 2f51ef6cfe..b2d15959a4 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java
+++ b/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java
@@ -89,9 +89,9 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
*/
@Inject
public ChainAuthenticatonManager(
- Set authenticationHandlerSet,
- EncryptionHandler encryptionHandler, CacheManager cacheManager,
- Provider> authenticationListenerProvider)
+ Set authenticationHandlerSet,
+ EncryptionHandler encryptionHandler, CacheManager cacheManager,
+ Provider> authenticationListenerProvider)
{
AssertUtil.assertIsNotEmpty(authenticationHandlerSet);
AssertUtil.assertIsNotNull(cacheManager);
@@ -99,8 +99,7 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
this.encryptionHandler = encryptionHandler;
this.authenticationListenerProvider = authenticationListenerProvider;
this.cache = cacheManager.getCache(String.class,
- AuthenticationCacheValue.class,
- CACHE_NAME);
+ AuthenticationCacheValue.class, CACHE_NAME);
// addListeners(authenticationListeners);
}
@@ -120,7 +119,7 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
*/
@Override
public AuthenticationResult authenticate(HttpServletRequest request,
- HttpServletResponse response, String username, String password)
+ HttpServletResponse response, String username, String password)
{
AssertUtil.assertIsNotEmpty(username);
AssertUtil.assertIsNotEmpty(password);
@@ -133,7 +132,7 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
if (logger.isTraceEnabled())
{
logger.trace("no authentication result for user {} found in cache",
- username);
+ username);
}
ar = doAuthentication(request, response, username, password);
@@ -141,7 +140,7 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
if ((ar != null) && ar.isCacheable())
{
cache.put(username,
- new AuthenticationCacheValue(ar, encryptedPassword));
+ new AuthenticationCacheValue(ar, encryptedPassword));
}
}
else if (logger.isDebugEnabled())
@@ -212,7 +211,7 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
* @return
*/
private AuthenticationResult doAuthentication(HttpServletRequest request,
- HttpServletResponse response, String username, String password)
+ HttpServletResponse response, String username, String password)
{
AuthenticationResult ar = null;
@@ -226,7 +225,7 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
if (logger.isTraceEnabled())
{
logger.trace("check authenticator {} for user {}",
- authenticator.getClass(), username);
+ authenticator.getClass(), username);
}
try
@@ -237,12 +236,12 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
if (logger.isDebugEnabled())
{
logger.debug("authenticator {} ends with result, {}",
- authenticator.getClass().getName(), result);
+ authenticator.getClass().getName(), result);
}
if ((result != null) && (result.getState() != null)
- && (result.getState().isSuccessfully()
- || (result.getState() == AuthenticationState.FAILED)))
+ && (result.getState().isSuccessfully()
+ || (result.getState() == AuthenticationState.FAILED)))
{
if (result.getState().isSuccessfully() && (result.getUser() != null))
{
@@ -260,7 +259,9 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
}
catch (Exception ex)
{
- logger.error(ex.getMessage(), ex);
+ logger.error(
+ "error durring authentication process of ".concat(
+ authenticator.getClass().getName()), ex);
}
}
@@ -279,7 +280,7 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
* @return
*/
private AuthenticationResult getCached(String username,
- String encryptedPassword)
+ String encryptedPassword)
{
AuthenticationResult result = null;
AuthenticationCacheValue value = cache.get(username);
@@ -326,7 +327,7 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
{
this.authenticationResult =
new AuthenticationResult(ar.getUser().clone(), ar.getGroups(),
- ar.getState());
+ ar.getState());
this.password = password;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAdministrationContext.java b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAdministrationContext.java
index 31c80b680f..3b9cc11224 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAdministrationContext.java
+++ b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAdministrationContext.java
@@ -30,19 +30,29 @@
*/
+
package sonia.scm.web.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Injector;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
-import com.google.inject.name.Named;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.SimplePrincipalCollection;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.subject.support.SubjectThreadState;
+import org.apache.shiro.util.ThreadContext;
+import org.apache.shiro.util.ThreadState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import sonia.scm.SCMContext;
+import sonia.scm.group.GroupNames;
+import sonia.scm.security.ScmRealm;
import sonia.scm.user.User;
import sonia.scm.util.AssertUtil;
@@ -77,15 +87,14 @@ public class DefaultAdministrationContext implements AdministrationContext
* @param injector
* @param userSessionProvider
* @param contextHolder
+ * @param securityManager
*/
@Inject
public DefaultAdministrationContext(Injector injector,
- @Named("userSession") Provider userSessionProvider,
- LocalSecurityContextHolder contextHolder)
+ org.apache.shiro.mgt.SecurityManager securityManager)
{
this.injector = injector;
- this.userSessionProvider = userSessionProvider;
- this.contextHolder = contextHolder;
+ this.securityManager = securityManager;
URL url = DefaultAdministrationContext.class.getResource(SYSTEM_ACCOUNT);
@@ -94,9 +103,9 @@ public class DefaultAdministrationContext implements AdministrationContext
throw new RuntimeException("could not find resource for system account");
}
- User user = JAXB.unmarshal(url, User.class);
+ User adminUser = JAXB.unmarshal(url, User.class);
- adminContext = new AdministrationSecurityContext(user);
+ principalCollection = createAdminCollection(adminUser);
}
//~--- methods --------------------------------------------------------------
@@ -112,24 +121,15 @@ public class DefaultAdministrationContext implements AdministrationContext
{
AssertUtil.assertIsNotNull(action);
- if (logger.isWarnEnabled())
+ if (ThreadContext.getSecurityManager() != null)
{
- String user = SecurityUtil.getUsername(userSessionProvider);
-
- logger.warn("user {} executes {} as admin", user,
- action.getClass().getName());
+ doRunAsInWebSessionContext(action);
+ }
+ else
+ {
+ doRunAsInNonWebSessionContext(action);
}
- contextHolder.set(adminContext);
-
- try
- {
- action.run();
- }
- finally
- {
- contextHolder.remove();
- }
}
/**
@@ -146,17 +146,136 @@ public class DefaultAdministrationContext implements AdministrationContext
runAsAdmin(action);
}
+ /**
+ * Method description
+ *
+ *
+ * @param adminUser
+ *
+ * @return
+ */
+ private PrincipalCollection createAdminCollection(User adminUser)
+ {
+ SimplePrincipalCollection collection = new SimplePrincipalCollection();
+
+ collection.add(adminUser.getId(), ScmRealm.NAME);
+ collection.add(adminUser, ScmRealm.NAME);
+ collection.add(new GroupNames(), ScmRealm.NAME);
+
+ return collection;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param action
+ */
+ private void doRunAsInNonWebSessionContext(PrivilegedAction action)
+ {
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("bind shiro security manager to current thread");
+ }
+
+ try
+ {
+ SecurityUtils.setSecurityManager(securityManager);
+
+ //J-
+ Subject subject = new Subject.Builder(securityManager)
+ .authenticated(true)
+ .principals(principalCollection)
+ .buildSubject();
+ //J+
+ ThreadState state = new SubjectThreadState(subject);
+
+ state.bind();
+
+ try
+ {
+ if (logger.isInfoEnabled())
+ {
+ logger.info("execute action {} in administration context",
+ action.getClass().getName());
+ }
+
+ action.run();
+ }
+ finally
+ {
+ state.clear();
+ }
+ }
+ finally
+ {
+ SecurityUtils.setSecurityManager(null);
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param action
+ */
+ private void doRunAsInWebSessionContext(PrivilegedAction action)
+ {
+ Subject subject = SecurityUtils.getSubject();
+
+ String principal = (String) subject.getPrincipal();
+
+ if (logger.isInfoEnabled())
+ {
+ String username = null;
+
+ if (subject.isAuthenticated())
+ {
+ username = principal;
+ }
+ else
+ {
+ username = SCMContext.USER_ANONYMOUS;
+ }
+
+ logger.info("user {} executes {} as admin", username,
+ action.getClass().getName());
+ }
+
+ subject.runAs(principalCollection);
+
+ try
+ {
+ action.run();
+ }
+ finally
+ {
+
+ PrincipalCollection collection = subject.releaseRunAs();
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("release runas for user {}",
+ collection.getPrimaryPrincipal());
+ }
+
+ if (!subject.getPrincipal().equals(principal))
+ {
+ logger.error("release runas failed, {} is not equal with {}, logout.",
+ subject.getPrincipal(), principal);
+ subject.logout();
+ }
+ }
+ }
+
//~--- fields ---------------------------------------------------------------
- /** Field description */
- private AdministrationSecurityContext adminContext;
-
- /** Field description */
- private LocalSecurityContextHolder contextHolder;
-
/** Field description */
private Injector injector;
/** Field description */
- private Provider userSessionProvider;
+ private PrincipalCollection principalCollection;
+
+ /** Field description */
+ private org.apache.shiro.mgt.SecurityManager securityManager;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/SecurityUtil.java b/scm-webapp/src/main/java/sonia/scm/web/security/SecurityUtil.java
index 84b735cfa4..e5b7f72e7e 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/security/SecurityUtil.java
+++ b/scm-webapp/src/main/java/sonia/scm/web/security/SecurityUtil.java
@@ -42,7 +42,9 @@ import sonia.scm.SCMContext;
/**
*
* @author Sebastian Sdorra
+ * @deprecated
*/
+@Deprecated
public class SecurityUtil
{
diff --git a/scm-webapp/src/main/resources/logback.default.xml b/scm-webapp/src/main/resources/logback.default.xml
index 8fa2d5cb5a..04e4a8c34a 100644
--- a/scm-webapp/src/main/resources/logback.default.xml
+++ b/scm-webapp/src/main/resources/logback.default.xml
@@ -50,7 +50,7 @@
-
+
diff --git a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java
index 6b710709c0..984dd8b105 100644
--- a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java
@@ -37,6 +37,9 @@ package sonia.scm.repository;
import com.google.inject.Provider;
+import org.apache.shiro.subject.Subject;
+
+import org.junit.Before;
import org.junit.Test;
import sonia.scm.Type;
@@ -93,6 +96,20 @@ public class DefaultRepositoryManagerTest extends RepositoryManagerTestBase
assertNull(m.getFromUri("/git/project1/test-3/ka/some/path"));
}
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ */
+ @Before
+ public void setAdminSubject()
+ {
+ Subject admin = MockUtil.createAdminSubject();
+
+ setSubject(admin);
+ }
+
//~--- methods --------------------------------------------------------------
/**
@@ -139,8 +156,8 @@ public class DefaultRepositoryManagerTest extends RepositoryManagerTestBase
ScmConfiguration configuration = new ScmConfiguration();
return new DefaultRepositoryManager(configuration, contextProvider,
- new DefaultKeyGenerator(), MockUtil.getAdminSecurityContextProvider(),
- repositoryDAO, handlerSet, listenerProvider, hookProvider);
+ new DefaultKeyGenerator(), repositoryDAO, handlerSet, listenerProvider,
+ hookProvider);
}
/**
diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/SecurityContextProvider.java b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionResolverTest.java
similarity index 54%
rename from scm-webapp/src/main/java/sonia/scm/web/security/SecurityContextProvider.java
rename to scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionResolverTest.java
index fae4f1dfb3..0b07d8992e 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/security/SecurityContextProvider.java
+++ b/scm-webapp/src/test/java/sonia/scm/security/RepositoryPermissionResolverTest.java
@@ -30,79 +30,74 @@
*/
-
-package sonia.scm.web.security;
+package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.name.Named;
+import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import sonia.scm.repository.PermissionType;
+
+import static org.junit.Assert.*;
/**
*
* @author Sebastian Sdorra
*/
-public class SecurityContextProvider implements Provider
+public class RepositoryPermissionResolverTest
{
- /** the logger for SecurityContextProvider */
- private static final Logger logger =
- LoggerFactory.getLogger(SecurityContextProvider.class);
-
- //~--- constructors ---------------------------------------------------------
-
- /**
- * Constructs ...
- *
- *
- * @param sessionContext
- * @param localContext
- */
- @Inject
- public SecurityContextProvider(
- @Named("userSession") Provider sessionContext,
- LocalSecurityContextHolder localContext)
- {
- this.sessionContext = sessionContext;
- this.localContext = localContext;
- }
-
- //~--- get methods ----------------------------------------------------------
-
/**
* Method description
*
- *
- * @return
*/
- @Override
- public WebSecurityContext get()
+ @Test
+ public void testResolvePermission()
{
- WebSecurityContext context = localContext.get();
+ RepositoryPermissionResolver resolver = new RepositoryPermissionResolver();
+ RepositoryPermission p = resolver.resolvePermission("repository:scm:read");
- if (context == null)
- {
- context = sessionContext.get();
- }
- else if (logger.isDebugEnabled())
- {
- String user = SecurityUtil.getUsername(sessionContext);
+ assertNotNull(p);
+ assertEquals("scm", p.getRepositoryId());
+ assertEquals(PermissionType.READ, p.getPermissionType());
- logger.debug("return system session for user {}", user);
- }
+ p = resolver.resolvePermission("repository:asd:wRitE");
+ assertNotNull(p);
+ assertEquals("asd", p.getRepositoryId());
+ assertEquals(PermissionType.WRITE, p.getPermissionType());
- return context;
+ p = resolver.resolvePermission("repository:*:OWNER");
+ assertNotNull(p);
+ assertEquals("*", p.getRepositoryId());
+ assertEquals(PermissionType.OWNER, p.getPermissionType());
}
- //~--- fields ---------------------------------------------------------------
+ /**
+ * Method description
+ *
+ */
+ @Test
+ public void testResolveUnknownPermission()
+ {
+ RepositoryPermissionResolver resolver = new RepositoryPermissionResolver();
+ RepositoryPermission p = resolver.resolvePermission("user:scm:read");
- /** Field description */
- private LocalSecurityContextHolder localContext;
+ assertNull(p);
- /** Field description */
- private Provider sessionContext;
+ p = resolver.resolvePermission("group:asd:wRitE");
+ assertNull(p);
+ }
+
+ /**
+ * Method description
+ *
+ */
+ @Test
+ public void testResolveUnknownTypePermission()
+ {
+ RepositoryPermissionResolver resolver = new RepositoryPermissionResolver();
+ RepositoryPermission p = resolver.resolvePermission("repository:scm:asd");
+
+ assertNull(p);
+ }
}
diff --git a/scm-webapp/src/test/java/sonia/scm/template/FreemarkerTemplateEngineTest.java b/scm-webapp/src/test/java/sonia/scm/template/FreemarkerTemplateEngineTest.java
index afc29bc487..ecb9b6270a 100644
--- a/scm-webapp/src/test/java/sonia/scm/template/FreemarkerTemplateEngineTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/template/FreemarkerTemplateEngineTest.java
@@ -1,34 +1,35 @@
/**
- * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ * Copyright (c) 2010, 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 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.
+ * 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.template;
//~--- JDK imports ------------------------------------------------------------
diff --git a/scm-webapp/src/test/java/sonia/scm/template/FreemarkerTemplateTest.java b/scm-webapp/src/test/java/sonia/scm/template/FreemarkerTemplateTest.java
index 03a42a1880..7a2fc17606 100644
--- a/scm-webapp/src/test/java/sonia/scm/template/FreemarkerTemplateTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/template/FreemarkerTemplateTest.java
@@ -1,34 +1,35 @@
/**
- * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ * Copyright (c) 2010, 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 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.
+ * 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.template;
//~--- non-JDK imports --------------------------------------------------------
diff --git a/scm-webapp/src/test/java/sonia/scm/template/MustacheTemplateEngineTest.java b/scm-webapp/src/test/java/sonia/scm/template/MustacheTemplateEngineTest.java
index b48082c660..4d1d15de49 100644
--- a/scm-webapp/src/test/java/sonia/scm/template/MustacheTemplateEngineTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/template/MustacheTemplateEngineTest.java
@@ -1,34 +1,35 @@
/**
- * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ * Copyright (c) 2010, 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 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.
+ * 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.template;
//~--- JDK imports ------------------------------------------------------------
diff --git a/scm-webapp/src/test/java/sonia/scm/template/MustacheTemplateTest.java b/scm-webapp/src/test/java/sonia/scm/template/MustacheTemplateTest.java
index dea361fc9f..186b809367 100644
--- a/scm-webapp/src/test/java/sonia/scm/template/MustacheTemplateTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/template/MustacheTemplateTest.java
@@ -1,34 +1,35 @@
/**
- * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ * Copyright (c) 2010, 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 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.
+ * 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.template;
//~--- non-JDK imports --------------------------------------------------------
diff --git a/scm-webapp/src/test/java/sonia/scm/template/TemplateEngineTestBase.java b/scm-webapp/src/test/java/sonia/scm/template/TemplateEngineTestBase.java
index f3d9714863..0be0908581 100644
--- a/scm-webapp/src/test/java/sonia/scm/template/TemplateEngineTestBase.java
+++ b/scm-webapp/src/test/java/sonia/scm/template/TemplateEngineTestBase.java
@@ -1,34 +1,35 @@
/**
- * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ * Copyright (c) 2010, 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 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.
+ * 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.template;
//~--- non-JDK imports --------------------------------------------------------
diff --git a/scm-webapp/src/test/java/sonia/scm/template/TemplateTestBase.java b/scm-webapp/src/test/java/sonia/scm/template/TemplateTestBase.java
index aa00529fc3..f192617049 100644
--- a/scm-webapp/src/test/java/sonia/scm/template/TemplateTestBase.java
+++ b/scm-webapp/src/test/java/sonia/scm/template/TemplateTestBase.java
@@ -1,34 +1,35 @@
/**
- * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ * Copyright (c) 2010, 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 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.
+ * 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.template;
//~--- non-JDK imports --------------------------------------------------------
diff --git a/scm-webapp/src/test/java/sonia/scm/user/DefaultUserManagerTest.java b/scm-webapp/src/test/java/sonia/scm/user/DefaultUserManagerTest.java
index 840aae469c..d18dac8bb6 100644
--- a/scm-webapp/src/test/java/sonia/scm/user/DefaultUserManagerTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/user/DefaultUserManagerTest.java
@@ -48,6 +48,7 @@ import static org.mockito.Mockito.*;
import java.util.HashSet;
import java.util.Set;
+import org.junit.Before;
/**
*
@@ -55,6 +56,11 @@ import java.util.Set;
*/
public class DefaultUserManagerTest extends UserManagerTestBase
{
+
+ @Before
+ public void setAdminSubject(){
+ setSubject(MockUtil.createAdminSubject());
+ }
/**
* Method description
@@ -74,8 +80,7 @@ public class DefaultUserManagerTest extends UserManagerTestBase
when(listenerProvider.get()).thenReturn(new HashSet());
XmlUserDAO userDAO = new XmlUserDAO(factory);
-
- return new DefaultUserManager(MockUtil.getAdminSecurityContextProvider(),
- userDAO, listenerProvider);
+
+ return new DefaultUserManager(userDAO, listenerProvider);
}
}
diff --git a/scm-webapp/src/test/java/sonia/scm/web/security/DefaultAuthenticationHandlerTest.java b/scm-webapp/src/test/java/sonia/scm/web/security/DefaultAuthenticationHandlerTest.java
index e9a2cc42b9..cdd3c2a116 100644
--- a/scm-webapp/src/test/java/sonia/scm/web/security/DefaultAuthenticationHandlerTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/web/security/DefaultAuthenticationHandlerTest.java
@@ -44,10 +44,11 @@ import sonia.scm.security.EncryptionHandler;
import sonia.scm.security.MessageDigestEncryptionHandler;
import sonia.scm.store.JAXBStoreFactory;
import sonia.scm.store.StoreFactory;
+import sonia.scm.user.DefaultUserManager;
import sonia.scm.user.User;
import sonia.scm.user.UserListener;
import sonia.scm.user.UserTestData;
-import sonia.scm.user.DefaultUserManager;
+import sonia.scm.user.xml.XmlUserDAO;
import sonia.scm.util.MockUtil;
import static org.junit.Assert.*;
@@ -61,7 +62,6 @@ import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import sonia.scm.user.xml.XmlUserDAO;
/**
*
@@ -141,13 +141,16 @@ public class DefaultAuthenticationHandlerTest extends AbstractTestBase
when(listenerProvider.get()).thenReturn(new HashSet());
XmlUserDAO userDAO = new XmlUserDAO(storeFactory);
-
- DefaultUserManager userManager =
- new DefaultUserManager(MockUtil.getAdminSecurityContextProvider(),
- userDAO, listenerProvider);
+
+ setSubject(MockUtil.createAdminSubject());
+
+ DefaultUserManager userManager = new DefaultUserManager(userDAO,
+ listenerProvider);
userManager.init(contextProvider);
userManager.create(slarti);
+ clearSubject();
+
handler = new DefaultAuthenticationHandler(userManager, enc);
handler.init(contextProvider);
request = MockUtil.getHttpServletRequest();
diff --git a/scm-webapp/src/test/resources/sonia/scm/template/002.ftl b/scm-webapp/src/test/resources/sonia/scm/template/002.ftl
index 4551c970e8..70257cdb5c 100644
--- a/scm-webapp/src/test/resources/sonia/scm/template/002.ftl
+++ b/scm-webapp/src/test/resources/sonia/scm/template/002.ftl
@@ -1 +1,33 @@
+<#--
+
+ Copyright (c) 2010, 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
+
+
+-->
Hello ${name}!
\ No newline at end of file
diff --git a/scm-webapp/src/test/resources/sonia/scm/template/004.ftl b/scm-webapp/src/test/resources/sonia/scm/template/004.ftl
index dfa2f00394..b83d5a6f4a 100644
--- a/scm-webapp/src/test/resources/sonia/scm/template/004.ftl
+++ b/scm-webapp/src/test/resources/sonia/scm/template/004.ftl
@@ -1 +1,33 @@
+<#--
+
+ Copyright (c) 2010, 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
+
+
+-->
Hello ${notAvailable}!
\ No newline at end of file
diff --git a/scm-webapp/src/test/resources/sonia/scm/template/006.ftl b/scm-webapp/src/test/resources/sonia/scm/template/006.ftl
index 99d266c61a..70f5780e79 100644
--- a/scm-webapp/src/test/resources/sonia/scm/template/006.ftl
+++ b/scm-webapp/src/test/resources/sonia/scm/template/006.ftl
@@ -1 +1,33 @@
+<#--
+
+ Copyright (c) 2010, 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
+
+
+-->
Hello #list>!
\ No newline at end of file