mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-01-31 03:39:14 +01:00
merge with branch apache-shiro
This commit is contained in:
3
pom.xml
3
pom.xml
@@ -401,6 +401,9 @@
|
||||
<freemarker.version>2.3.19</freemarker.version>
|
||||
<jetty.version>7.6.7.v20120910</jetty.version>
|
||||
|
||||
<!-- security libraries -->
|
||||
<shiro.version>1.2.1</shiro.version>
|
||||
|
||||
<!-- repostitory libraries -->
|
||||
<jgit.version>2.1.0.201209190230-r</jgit.version>
|
||||
<svnkit.version>1.7.5-2</svnkit.version>
|
||||
|
||||
@@ -23,10 +23,50 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--
|
||||
scm-core with excludes.
|
||||
TODO: create a module only for data objects.
|
||||
-->
|
||||
|
||||
<dependency>
|
||||
<groupId>sonia.scm</groupId>
|
||||
<artifactId>scm-core</artifactId>
|
||||
<groupId>sonia.scm</groupId>
|
||||
<type>jar</type>
|
||||
<version>1.21-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>aopalliance</artifactId>
|
||||
<groupId>aopalliance</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guice</artifactId>
|
||||
<groupId>com.google.inject</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guice-multibindings</artifactId>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guice-servlet</artifactId>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jersey-core</artifactId>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guice-throwingproviders</artifactId>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<groupId>commons-lang</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -32,26 +32,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<artifactId>scm-core</artifactId>
|
||||
<groupId>sonia.scm</groupId>
|
||||
<version>1.21-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>guice</artifactId>
|
||||
<groupId>com.google.inject</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guice-servlet</artifactId>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guice-multibindings</artifactId>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>sonia.scm.clients</groupId>
|
||||
<artifactId>scm-client-impl</artifactId>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<version>1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -33,30 +33,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<artifactId>scm-core</artifactId>
|
||||
<groupId>sonia.scm</groupId>
|
||||
<version>1.21-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>aopalliance</artifactId>
|
||||
<groupId>aopalliance</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guice</artifactId>
|
||||
<groupId>com.google.inject</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guice-multibindings</artifactId>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guice-servlet</artifactId>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>sonia.scm.clients</groupId>
|
||||
<artifactId>scm-client-api</artifactId>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -33,6 +33,14 @@
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- security -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<version>${shiro.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- injection -->
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -73,10 +73,10 @@ public class ScmState
|
||||
* @param repositoryTypes - available repository types
|
||||
* @param clientConfig - client configuration
|
||||
*/
|
||||
@Deprecated
|
||||
public ScmState(SCMContextProvider provider,
|
||||
WebSecurityContext securityContext,
|
||||
Collection<Type> repositoryTypes,
|
||||
ScmClientConfig clientConfig)
|
||||
WebSecurityContext securityContext, Collection<Type> 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<Type> repositoryTypes, String defaultUserType,
|
||||
ScmClientConfig clientConfig)
|
||||
WebSecurityContext securityContext, Collection<Type> 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<String> groups, Collection<Type> 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 ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<String>
|
||||
{
|
||||
|
||||
/** 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<String> 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<String> 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<String> getGroups()
|
||||
public Collection<String> 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<String> groups = new ArrayList<String>();
|
||||
|
||||
/** Field description */
|
||||
private User user;
|
||||
private Collection<String> collection;
|
||||
}
|
||||
@@ -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<WebSecurityContext> securityContextProvider,
|
||||
PermissionType pt)
|
||||
Provider<WebSecurityContext> 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<WebSecurityContext> securityContextProvider,
|
||||
PermissionType pt)
|
||||
Provider<WebSecurityContext> 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<Permission> permissions = repository.getPermissions();
|
||||
|
||||
AssertUtil.assertIsNotEmpty(username);
|
||||
|
||||
if (user.isAdmin()
|
||||
|| ((pt == PermissionType.READ) && repository.isPublicReadable()))
|
||||
if (permissions != null)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Permission> 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<Permission> permissions,
|
||||
String username, Collection<String> 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;
|
||||
|
||||
|
||||
@@ -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<WebSecurityContext> securityContextProvider,
|
||||
Set<RepositoryServiceResolver> 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<RepositoryServiceResolver> 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<RepositoryServiceResolver> resolvers;
|
||||
|
||||
/** Field description */
|
||||
private Provider<WebSecurityContext> securityContextProvider;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
48
scm-core/src/main/java/sonia/scm/security/Role.java
Normal file
48
scm-core/src/main/java/sonia/scm/security/Role.java
Normal file
@@ -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";
|
||||
}
|
||||
@@ -40,7 +40,9 @@ import sonia.scm.user.User;
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @deprecated use {@link SecurityUtils#getSecurityManager()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface SecurityContext
|
||||
{
|
||||
|
||||
|
||||
70
scm-core/src/main/java/sonia/scm/security/Tokens.java
Normal file
70
scm-core/src/main/java/sonia/scm/security/Tokens.java
Normal file
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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 ------------------------------------------------------------
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> securityContextProvider) {}
|
||||
|
||||
/**
|
||||
* Constructs a new basic authenticaton filter
|
||||
*
|
||||
* @param configuration scm-manager global configuration
|
||||
*
|
||||
* @since 1.21
|
||||
*/
|
||||
@Inject
|
||||
public BasicAuthenticationFilter(
|
||||
Provider<WebSecurityContext> 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<WebSecurityContext> securityContextProvider;
|
||||
private ScmConfiguration configuration;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> securityContextProvider)
|
||||
Provider<WebSecurityContext> 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<String> 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<WebSecurityContext> securityContextProvider;
|
||||
|
||||
/** Field description */
|
||||
private ScmConfiguration configuration;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> securityContextProvider,
|
||||
RepositoryProvider repositoryProvider)
|
||||
@Deprecated
|
||||
public ProviderPermissionFilter(ScmConfiguration configuration,
|
||||
Provider<WebSecurityContext> 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())
|
||||
{
|
||||
|
||||
@@ -71,15 +71,31 @@ public abstract class RegexPermissionFilter extends PermissionFilter
|
||||
* @param securityContextProvider
|
||||
* @param repositoryManager
|
||||
*/
|
||||
public RegexPermissionFilter(
|
||||
ScmConfiguration configuration,
|
||||
Provider<WebSecurityContext> 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<WebSecurityContext> securityContextProvider,
|
||||
RepositoryManager repositoryManager)
|
||||
{
|
||||
this(configuration, repositoryManager);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
|
||||
@@ -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<Permission>(
|
||||
Arrays.asList(
|
||||
new Permission("dent"),
|
||||
new Permission("devel", PermissionType.WRITE, true),
|
||||
new ArrayList<Permission>(
|
||||
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 --------------------------------------------------------------
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
@@ -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 --------------------------------------------------------
|
||||
|
||||
@@ -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 <T> JAXBStore<T> getStore(Class<T> 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<T>(type, configFile);
|
||||
|
||||
@@ -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<WebSecurityContext> securityContextProvider,
|
||||
RepositoryProvider repositoryProvider)
|
||||
{
|
||||
super(configuration, securityContextProvider, repositoryProvider);
|
||||
super(configuration, repositoryProvider);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@@ -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<HgContext> contextProvider,
|
||||
Provider<WebSecurityContext> securityContextProvider)
|
||||
public HgHookCallbackServlet(RepositoryManager repositoryManager,
|
||||
HgRepositoryHandler handler, HgHookManager hookManager,
|
||||
Provider<HgContext> 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<WebSecurityContext> securityContextProvider;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> securityContextProvider,
|
||||
RepositoryProvider repositoryProvider)
|
||||
public HgPermissionFilter(ScmConfiguration configuration,
|
||||
RepositoryProvider repositoryProvider)
|
||||
{
|
||||
super(configuration, securityContextProvider, repositoryProvider);
|
||||
super(configuration, repositoryProvider);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@@ -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<WebSecurityContext> securityContextProvider,
|
||||
RepositoryProvider repository)
|
||||
public SvnPermissionFilter(ScmConfiguration configuration,
|
||||
RepositoryProvider repository)
|
||||
{
|
||||
super(configuration, securityContextProvider, repository);
|
||||
super(configuration, repository);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@@ -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<SecurityContext> 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 ----------------------------------------------------------
|
||||
|
||||
@@ -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 ---------------------------------------------------------------
|
||||
|
||||
@@ -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<User, UserException>
|
||||
extends ManagerTestBase<User, UserException>
|
||||
{
|
||||
|
||||
/** 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<MultiThreadTester> testers = new ArrayList<MultiThreadTester>();
|
||||
@@ -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");
|
||||
|
||||
@@ -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<Boolean[]>()
|
||||
{
|
||||
|
||||
@Override
|
||||
public Boolean[] answer(InvocationOnMock invocation) throws Throwable
|
||||
{
|
||||
List<Permission> permissions =
|
||||
(List<Permission>) 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
|
||||
*
|
||||
|
||||
@@ -64,6 +64,20 @@
|
||||
<artifactId>scm-git-plugin</artifactId>
|
||||
<version>1.21-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- security -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-web</artifactId>
|
||||
<version>${shiro.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-guice</artifactId>
|
||||
<version>${shiro.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- rest api -->
|
||||
|
||||
|
||||
@@ -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<Module> moduleList = new ArrayList<Module>();
|
||||
List<Module> 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;
|
||||
}
|
||||
|
||||
149
scm-webapp/src/main/java/sonia/scm/ScmInitializerModule.java
Normal file
149
scm-webapp/src/main/java/sonia/scm/ScmInitializerModule.java
Normal file
@@ -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 <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter)
|
||||
{
|
||||
encounter.register(new InjectionListener<I>()
|
||||
{
|
||||
@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<TypeLiteral<?>> isSubtypeOf(final Class<?> supertype)
|
||||
{
|
||||
return isSubtypeOf(TypeLiteral.get(supertype));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param supertype
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Matcher<TypeLiteral<?>> isSubtypeOf(final TypeLiteral<?> supertype)
|
||||
{
|
||||
return new AbstractMatcher<TypeLiteral<?>>()
|
||||
{
|
||||
@Override
|
||||
public boolean matches(TypeLiteral<?> type)
|
||||
{
|
||||
return typeIsSubtypeOf(type, supertype);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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<WebSecurityContext> store =
|
||||
new ThreadLocal<WebSecurityContext>();
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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<WebSecurityContext> 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<String> 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<WebSecurityContext> securityContextProvider;
|
||||
|
||||
/** Field description */
|
||||
private UserManager userManager;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> 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<WebSecurityContext> securityContextProvider;
|
||||
|
||||
/** Field description */
|
||||
private UserManager userManager;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> 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<WebSecurityContext> securityContextProvider;
|
||||
}
|
||||
|
||||
@@ -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<Group, GroupException>
|
||||
extends AbstractManagerResource<Group, GroupException>
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
@@ -94,11 +95,9 @@ public class GroupResource
|
||||
* @param groupManager
|
||||
*/
|
||||
@Inject
|
||||
public GroupResource(Provider<WebSecurityContext> 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<Collection<Group>> createGenericEntity(
|
||||
Collection<Group> items)
|
||||
Collection<Group> items)
|
||||
{
|
||||
return new GenericEntity<Collection<Group>>(items) {}
|
||||
;
|
||||
@@ -294,9 +293,4 @@ public class GroupResource
|
||||
{
|
||||
return PATH_PART;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private Provider<WebSecurityContext> securityContextProvider;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> 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<List<Repository>> importRepositories(
|
||||
@PathParam("type") String type)
|
||||
@PathParam("type") String type)
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(securityContextProvider);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
List<Repository> repositories = new ArrayList<Repository>();
|
||||
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<List<Type>> getImportableTypes()
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(securityContextProvider);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
List<Type> types = new ArrayList<Type>();
|
||||
Collection<Type> 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<WebSecurityContext> securityContextProvider;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> 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<WebSecurityContext> securityContextProvider;
|
||||
|
||||
/** Field description */
|
||||
private RepositoryServiceFactory servicefactory;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> 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<String, SearchResults> userCache =
|
||||
cacheManager.getCache(String.class, SearchResults.class, CACHE_USER);
|
||||
|
||||
this.userSearchHandler = new SearchHandler<User>(securityContextProvider,
|
||||
userCache, userManager);
|
||||
this.userSearchHandler = new SearchHandler<User>(userCache, userManager);
|
||||
|
||||
// create group searchhandler
|
||||
groupManager.addListener(this);
|
||||
@@ -112,8 +108,8 @@ public class SearchResource implements UserListener, GroupListener
|
||||
Cache<String, SearchResults> groupCache =
|
||||
cacheManager.getCache(String.class, SearchResults.class, CACHE_GROUP);
|
||||
|
||||
this.groupSearchHandler = new SearchHandler<Group>(securityContextProvider,
|
||||
groupCache, groupManager);
|
||||
this.groupSearchHandler = new SearchHandler<Group>(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<Group, SearchResult>()
|
||||
new Function<Group, SearchResult>()
|
||||
{
|
||||
@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<User, SearchResult>()
|
||||
new Function<User, SearchResult>()
|
||||
{
|
||||
@Override
|
||||
public SearchResult apply(User user)
|
||||
|
||||
@@ -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<String, Object> 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;
|
||||
}
|
||||
|
||||
@@ -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<User, UserException>
|
||||
*/
|
||||
@Inject
|
||||
public UserResource(UserManager userManager,
|
||||
EncryptionHandler encryptionHandler,
|
||||
Provider<WebSecurityContext> securityContextProvider)
|
||||
EncryptionHandler encryptionHandler)
|
||||
{
|
||||
super(userManager);
|
||||
this.encryptionHandler = encryptionHandler;
|
||||
this.securityContextProvider = securityContextProvider;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
@@ -179,7 +177,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
@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<User, UserException>
|
||||
{
|
||||
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<User, UserException>
|
||||
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<User, UserException>
|
||||
*/
|
||||
@Override
|
||||
protected GenericEntity<Collection<User>> createGenericEntity(
|
||||
Collection<User> items)
|
||||
Collection<User> items)
|
||||
{
|
||||
return new GenericEntity<Collection<User>>(items) {}
|
||||
;
|
||||
@@ -396,7 +394,4 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
|
||||
/** Field description */
|
||||
private EncryptionHandler encryptionHandler;
|
||||
|
||||
/** Field description */
|
||||
private Provider<WebSecurityContext> securityContextProvider;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> 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<WebSecurityContext> securityContextProvider;
|
||||
private ScmConfiguration configuration;
|
||||
}
|
||||
|
||||
@@ -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<SecurityContext> securityContextProvider,
|
||||
GroupDAO groupDAO,
|
||||
public DefaultGroupManager(GroupDAO groupDAO,
|
||||
Provider<Set<GroupListener>> 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<Group> getAll(Comparator<Group> comparator)
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(securityContextProvider);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
List<Group> groups = new ArrayList<Group>();
|
||||
|
||||
@@ -378,7 +375,7 @@ public class DefaultGroupManager extends AbstractGroupManager
|
||||
public Collection<Group> getAll(Comparator<Group> comparator, int start,
|
||||
int limit)
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(securityContextProvider);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
return Util.createSubCollection(groupDAO.getAll(), comparator,
|
||||
new CollectionAppender<Group>()
|
||||
@@ -449,7 +446,4 @@ public class DefaultGroupManager extends AbstractGroupManager
|
||||
|
||||
/** Field description */
|
||||
private Provider<Set<GroupListener>> groupListenerProvider;
|
||||
|
||||
/** Field description */
|
||||
private Provider<SecurityContext> securityContextProvider;
|
||||
}
|
||||
|
||||
@@ -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<SecurityContext> securityContextProvicer,
|
||||
ScmConfiguration configuration, PluginLoader pluginLoader,
|
||||
CacheManager cacheManager, Provider<HttpClient> 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<PluginInformation> get(PluginFilter filter)
|
||||
{
|
||||
AssertUtil.assertIsNotNull(filter);
|
||||
SecurityUtil.assertIsAdmin(securityContextProvicer);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
Set<PluginInformation> infoSet = new HashSet<PluginInformation>();
|
||||
|
||||
@@ -412,7 +409,7 @@ public class DefaultPluginManager
|
||||
@Override
|
||||
public Collection<PluginInformation> getAll()
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(securityContextProvicer);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
Set<PluginInformation> infoSet = getInstalled();
|
||||
|
||||
@@ -430,7 +427,7 @@ public class DefaultPluginManager
|
||||
@Override
|
||||
public Collection<PluginInformation> getAvailable()
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(securityContextProvicer);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
Set<PluginInformation> availablePlugins = new HashSet<PluginInformation>();
|
||||
Set<PluginInformation> centerPlugins = getPluginCenter().getPlugins();
|
||||
@@ -455,7 +452,7 @@ public class DefaultPluginManager
|
||||
@Override
|
||||
public Set<PluginInformation> getAvailableUpdates()
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(securityContextProvicer);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
return get(FILTER_UPDATES);
|
||||
}
|
||||
@@ -469,7 +466,7 @@ public class DefaultPluginManager
|
||||
@Override
|
||||
public Set<PluginInformation> getInstalled()
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(securityContextProvicer);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
Set<PluginInformation> infoSet = new LinkedHashSet<PluginInformation>();
|
||||
|
||||
@@ -765,9 +762,6 @@ public class DefaultPluginManager
|
||||
/** Field description */
|
||||
private AetherPluginHandler pluginHandler;
|
||||
|
||||
/** Field description */
|
||||
private Provider<SecurityContext> securityContextProvicer;
|
||||
|
||||
/** Field description */
|
||||
private Unmarshaller unmarshaller;
|
||||
}
|
||||
|
||||
@@ -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<WebSecurityContext> securityContextProvider,
|
||||
RepositoryDAO repositoryDAO, Set<RepositoryHandler> handlerSet,
|
||||
Provider<Set<RepositoryListener>> repositoryListenersProvider,
|
||||
Provider<Set<RepositoryHook>> 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<String, RepositoryHandler>();
|
||||
types = new HashSet<Type>();
|
||||
|
||||
@@ -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<Repository> getAll(Comparator<Repository> comparator)
|
||||
{
|
||||
List<Repository> repositories = new ArrayList<Repository>();
|
||||
List<Repository> repositories = Lists.newArrayList();
|
||||
|
||||
for (Repository repository : repositoryDAO.getAll())
|
||||
{
|
||||
@@ -603,7 +601,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
|
||||
@Override
|
||||
public Collection<Type> getConfiguredTypes()
|
||||
{
|
||||
List<Type> validTypes = new ArrayList<Type>();
|
||||
List<Type> 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<Set<RepositoryListener>> repositoryListenersProvider;
|
||||
|
||||
/** Field description */
|
||||
private Provider<WebSecurityContext> securityContextProvider;
|
||||
|
||||
/** Field description */
|
||||
private Set<Type> types;
|
||||
}
|
||||
|
||||
@@ -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<T>
|
||||
* @param cache
|
||||
* @param searchable
|
||||
*/
|
||||
public SearchHandler(Provider<WebSecurityContext> securityContextProvider,
|
||||
Cache<String, SearchResults> cache,
|
||||
Searchable<T> searchable)
|
||||
public SearchHandler(Cache<String, SearchResults> cache,
|
||||
Searchable<T> searchable)
|
||||
{
|
||||
this.securityContextProvider = securityContextProvider;
|
||||
|
||||
this.cache = cache;
|
||||
this.searchable = searchable;
|
||||
}
|
||||
@@ -107,9 +107,14 @@ public class SearchHandler<T>
|
||||
* @return
|
||||
*/
|
||||
public SearchResults search(String queryString,
|
||||
Function<T, SearchResult> function)
|
||||
Function<T, SearchResult> 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<T>
|
||||
/** Field description */
|
||||
protected Searchable<T> searchable;
|
||||
|
||||
/** Field description */
|
||||
protected Provider<WebSecurityContext> securityContextProvider;
|
||||
|
||||
/** Field description */
|
||||
private int maxResults = 5;
|
||||
|
||||
|
||||
@@ -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<String> 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<String> 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;
|
||||
}
|
||||
}
|
||||
777
scm-webapp/src/main/java/sonia/scm/security/ScmRealm.java
Normal file
777
scm-webapp/src/main/java/sonia/scm/security/ScmRealm.java
Normal file
@@ -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<HttpServletRequest> requestProvider,
|
||||
Provider<HttpServletResponse> 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<String> authenticate(HttpServletRequest request, String password,
|
||||
AuthenticationResult ar)
|
||||
{
|
||||
Set<String> 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<String> 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<org.apache.shiro.authz.Permission> collectRepositoryPermissions(
|
||||
User user, GroupNames groups)
|
||||
{
|
||||
List<org.apache.shiro.authz.Permission> 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<org.apache.shiro.authz.Permission> permissions, Repository repository,
|
||||
User user, GroupNames groups)
|
||||
{
|
||||
List<Permission> 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<String> 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<String> roles = Sets.newHashSet();
|
||||
List<org.apache.shiro.authz.Permission> 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<String> createGroupSet(AuthenticationResult ar)
|
||||
{
|
||||
Set<String> groupSet = Sets.newHashSet();
|
||||
|
||||
// load external groups
|
||||
Collection<String> 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<String> groupSet)
|
||||
{
|
||||
Collection<Group> 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<String> 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<String> groups)
|
||||
{
|
||||
boolean result = false;
|
||||
Set<String> adminUsers = configuration.getAdminUsers();
|
||||
|
||||
if (adminUsers != null)
|
||||
{
|
||||
result = adminUsers.contains(user.getName());
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Set<String> 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<String, AuthorizationInfo> cache;
|
||||
|
||||
/** Field description */
|
||||
private ScmConfiguration configuration;
|
||||
|
||||
/** Field description */
|
||||
private GroupManager groupManager;
|
||||
|
||||
/** Field description */
|
||||
private RepositoryDAO repositoryDAO;
|
||||
|
||||
/** Field description */
|
||||
private Provider<HttpServletRequest> requestProvider;
|
||||
|
||||
/** Field description */
|
||||
private Provider<HttpServletResponse> responseProvider;
|
||||
|
||||
/** Field description */
|
||||
private UserDAO userDAO;
|
||||
|
||||
/** Field description */
|
||||
private UserManager userManager;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<WebSecurityContext> scurityContextProvider, UserDAO userDAO,
|
||||
Provider<Set<UserListener>> userListenerProvider)
|
||||
public DefaultUserManager(UserDAO userDAO,
|
||||
Provider<Set<UserListener>> 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<User>()
|
||||
new TransformFilter<User>()
|
||||
{
|
||||
@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<User> getAll(Comparator<User> comparator)
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(scurityContextProvider);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
List<User> users = new ArrayList<User>();
|
||||
|
||||
@@ -424,12 +438,12 @@ public class DefaultUserManager extends AbstractUserManager
|
||||
*/
|
||||
@Override
|
||||
public Collection<User> getAll(Comparator<User> comaparator, int start,
|
||||
int limit)
|
||||
int limit)
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(scurityContextProvider);
|
||||
SecurityUtil.assertIsAdmin();
|
||||
|
||||
return Util.createSubCollection(userDAO.getAll(), comaparator,
|
||||
new CollectionAppender<User>()
|
||||
new CollectionAppender<User>()
|
||||
{
|
||||
@Override
|
||||
public void append(Collection<User> 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<WebSecurityContext> scurityContextProvider;
|
||||
|
||||
/** Field description */
|
||||
private UserDAO userDAO;
|
||||
|
||||
|
||||
76
scm-webapp/src/main/java/sonia/scm/user/UserEventHack.java
Normal file
76
scm-webapp/src/main/java/sonia/scm/user/UserEventHack.java
Normal file
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<WebSecurityContext> 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);
|
||||
}
|
||||
|
||||
@@ -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<String>();
|
||||
SecurityUtils.getSubject().logout();
|
||||
|
||||
HttpSession session = request.getSession(false);
|
||||
|
||||
@@ -174,12 +166,20 @@ public class BasicSecurityContext implements WebSecurityContext
|
||||
@Override
|
||||
public Collection<String> getGroups()
|
||||
{
|
||||
if (groups == null)
|
||||
GroupNames groups = getPrincipal(GroupNames.class);
|
||||
|
||||
Collection<String> groupCollection = null;
|
||||
|
||||
if (groups != null)
|
||||
{
|
||||
groups = new HashSet<String>();
|
||||
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<String> 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<String> 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 <T>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Set<String> createGroupSet(AuthenticationResult ar)
|
||||
private <T> T getPrincipal(Class<T> clazz)
|
||||
{
|
||||
Set<String> groupSet = Sets.newHashSet();
|
||||
T result = null;
|
||||
Subject subject = SecurityUtils.getSubject();
|
||||
|
||||
// load external groups
|
||||
Collection<String> 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<String> groupSet)
|
||||
{
|
||||
Collection<Group> 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<String> 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<String> groups)
|
||||
{
|
||||
boolean result = false;
|
||||
Set<String> adminUsers = configuration.getAdminUsers();
|
||||
|
||||
if (adminUsers != null)
|
||||
{
|
||||
result = adminUsers.contains(user.getName());
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Set<String> 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<String> groups = new HashSet<String>();
|
||||
|
||||
/** Field description */
|
||||
private User user;
|
||||
|
||||
/** Field description */
|
||||
private UserManager userManager;
|
||||
}
|
||||
|
||||
@@ -89,9 +89,9 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager
|
||||
*/
|
||||
@Inject
|
||||
public ChainAuthenticatonManager(
|
||||
Set<AuthenticationHandler> authenticationHandlerSet,
|
||||
EncryptionHandler encryptionHandler, CacheManager cacheManager,
|
||||
Provider<Set<AuthenticationListener>> authenticationListenerProvider)
|
||||
Set<AuthenticationHandler> authenticationHandlerSet,
|
||||
EncryptionHandler encryptionHandler, CacheManager cacheManager,
|
||||
Provider<Set<AuthenticationListener>> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<WebSecurityContext> 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<WebSecurityContext> userSessionProvider;
|
||||
private PrincipalCollection principalCollection;
|
||||
|
||||
/** Field description */
|
||||
private org.apache.shiro.mgt.SecurityManager securityManager;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,9 @@ import sonia.scm.SCMContext;
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public class SecurityUtil
|
||||
{
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="sonia.scm" level="DEBUG" />
|
||||
<logger name="sonia.scm" level="TRACE" />
|
||||
|
||||
<!-- suppress massive gzip logging -->
|
||||
<logger name="sonia.scm.filter.GZipFilter" level="WARN" />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<WebSecurityContext>
|
||||
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<WebSecurityContext> 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<WebSecurityContext> 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);
|
||||
}
|
||||
}
|
||||
@@ -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 ------------------------------------------------------------
|
||||
|
||||
@@ -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 --------------------------------------------------------
|
||||
|
||||
@@ -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 ------------------------------------------------------------
|
||||
|
||||
@@ -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 --------------------------------------------------------
|
||||
|
||||
@@ -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 --------------------------------------------------------
|
||||
|
||||
@@ -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 --------------------------------------------------------
|
||||
|
||||
@@ -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<UserListener>());
|
||||
|
||||
XmlUserDAO userDAO = new XmlUserDAO(factory);
|
||||
|
||||
return new DefaultUserManager(MockUtil.getAdminSecurityContextProvider(),
|
||||
userDAO, listenerProvider);
|
||||
|
||||
return new DefaultUserManager(userDAO, listenerProvider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<UserListener>());
|
||||
|
||||
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();
|
||||
|
||||
@@ -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}!
|
||||
@@ -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}!
|
||||
@@ -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>!
|
||||
Reference in New Issue
Block a user