Commits

Sebastian Sdorra committed a801cf2

fix anonymous access

Comments (0)

Files changed (9)

scm-core/src/main/java/sonia/scm/repository/PermissionUtil.java

   @Deprecated
   public static void assertPermission(Repository repository, PermissionType pt)
   {
-    if (!hasPermission(repository, pt))
+    if (!hasPermission(null, repository, pt))
     {
       throw new ScmSecurityException("action denied");
     }
   public static boolean hasPermission(Repository repository,
     Provider<WebSecurityContext> securityContextProvider, PermissionType pt)
   {
-    return hasPermission(repository, securityContextProvider.get(), pt);
+    return hasPermission(null, repository, pt);
   }
 
   /**
   public static boolean hasPermission(Repository repository,
     WebSecurityContext securityContext, PermissionType pt)
   {
-    return hasPermission(repository, pt);
+    return hasPermission(null, repository, pt);
   }
 
   /**
    * Method description
    *
    *
+   * @param configuration
    * @param repository
-   * @param securityContext
    * @param pt
    *
    * @return
+   *
    * @since 1.21
-   *
-   * @deprecated
    */
-  @Deprecated
-  public static boolean hasPermission(Repository repository, PermissionType pt)
+  public static boolean hasPermission(ScmConfiguration configuration,
+    Repository repository, PermissionType pt)
   {
     boolean result = false;
 
 
     if (subject.isAuthenticated())
     {
-
       String username = subject.getPrincipal().toString();
 
       AssertUtil.assertIsNotEmpty(username);
         }
       }
     }
+    else
+    {
+
+      // check anonymous access
+      result = (configuration != null)
+        && configuration.isAnonymousAccessEnabled()
+        && repository.isPublicReadable() && (pt == PermissionType.READ);
+    }
 
     return result;
   }
     }
     else
     {
-      permitted = PermissionUtil.hasPermission(repository,
+      permitted = PermissionUtil.hasPermission(configuration, repository,
         PermissionType.WRITE);
     }
 

scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java

 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.subject.Subject;
-
 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.repository.BlameResult;
 import sonia.scm.repository.Branches;
 import sonia.scm.repository.BrowserResult;
 import sonia.scm.repository.ChangesetPagingResult;
 import sonia.scm.repository.PermissionType;
+import sonia.scm.repository.PermissionUtil;
 import sonia.scm.repository.PostReceiveRepositoryHook;
 import sonia.scm.repository.PreProcessorUtil;
 import sonia.scm.repository.Repository;
 import sonia.scm.repository.Tags;
 import sonia.scm.repository.spi.RepositoryServiceProvider;
 import sonia.scm.repository.spi.RepositoryServiceResolver;
-import sonia.scm.security.RepositoryPermission;
 import sonia.scm.security.ScmSecurityException;
 
 //~--- JDK imports ------------------------------------------------------------
    * @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,
     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.resolvers = resolvers;
     Preconditions.checkNotNull(repository, "repository is required");
 
     // check for read permissions of current user
-    Subject subject = SecurityUtils.getSubject();
-
-    if (!subject.isPermitted(new RepositoryPermission(repository,
-      PermissionType.READ)))
+    if (!PermissionUtil.hasPermission(configuration, repository,
+      PermissionType.READ))
     {
       throw new ScmSecurityException("read permission are required");
     }
   /** Field description */
   private CacheManager cacheManager;
 
+  /** scm-manager configuration */
+  private ScmConfiguration configuration;
+
   /** Field description */
   private PreProcessorUtil preProcessorUtil;
 

scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java

 
 //~--- non-JDK imports --------------------------------------------------------
 
+import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import sonia.scm.SCMContext;
+import sonia.scm.config.ScmConfiguration;
 import sonia.scm.security.ScmAuthenticationToken;
 import sonia.scm.user.User;
 import sonia.scm.util.HttpUtil;
 
   /**
    * Constructs ...
-   * @since 1.21
-   */
-  public BasicAuthenticationFilter() {}
-
-  /**
-   * Constructs ...
    *
    *
    * @param securityContextProvider
   public BasicAuthenticationFilter(
     Provider<WebSecurityContext> securityContextProvider) {}
 
+  /**
+   * Constructs a new basic authenticaton filter
+   *
+   * @param configuration scm-manager global configuration
+   *
+   * @since 1.21
+   */
+  @Inject
+  public BasicAuthenticationFilter(ScmConfiguration configuration)
+  {
+    this.configuration = configuration;
+  }
+
   //~--- methods --------------------------------------------------------------
 
   /**
 
       user = subject.getPrincipals().oneByType(User.class);
     }
+    else if ((configuration != null)
+      && configuration.isAnonymousAccessEnabled())
+    {
+      user = new User(SCMContext.USER_ANONYMOUS, "SCM Anonymous",
+        "scm-anonymous@scm-manager.com");
+
+    }
 
     if (user == null)
     {
 
     return user;
   }
+
+  //~--- fields ---------------------------------------------------------------
+
+  /** Field description */
+  private ScmConfiguration configuration;
 }

scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java

 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;
   //~--- constructors ---------------------------------------------------------
 
   /**
-   * Constructs ...
-   *
-   *
-   *
-   * @param configuration
-   * @param securityContextProvider
+   * Constructs a new permission filter
+   * 
+   * @param configuration global scm-manager configuration
+   * 
+   * @since 1.21
    */
   public PermissionFilter(ScmConfiguration configuration)
   {
   {
     Subject subject = SecurityUtils.getSubject();
 
-    if (subject.isAuthenticated())
+    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 (logger.isTraceEnabled())
+          {
+            logger.trace("{} access to repository {} for user {} granted",
+              new Object[] { writeRequest
+              ? "write"
+              : "read", repository.getName(), subject.getPrincipal() });
+          }
 
-          if (hasPermission(repository, writeRequest))
-          {
-            if (logger.isTraceEnabled())
-            {
-              logger.trace("{} access to repository {} for user {} granted",
-                new Object[] { writeRequest
-                ? "write"
-                : "read", repository.getName(), subject.getPrincipal() });
-            }
-
-            chain.doFilter(request, response);
-          }
-          else
-          {
-            if (logger.isInfoEnabled())
-            {
-              logger.info("{} access to repository {} for user {} denied",
-                new Object[] { writeRequest
-                ? "write"
-                : "read", repository.getName(), subject.getPrincipal() });
-            }
-
-            sendAccessDenied(response, subject);
-          }
+          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",
-            subject.getPrincipal());
-        }
-
-        sendAccessDenied(response, subject);
+        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);
+    }
+
   }
 
   /**
   private void sendAccessDenied(HttpServletResponse response, Subject subject)
     throws IOException
   {
-
-    // TODO check anonymous access
-    if (SCMContext.USER_ANONYMOUS.equals(subject.getPrincipal()))
+    if (subject.isAuthenticated())
     {
-      HttpUtil.sendUnauthorized(response);
+      response.sendError(HttpServletResponse.SC_FORBIDDEN);
     }
     else
     {
-      response.sendError(HttpServletResponse.SC_FORBIDDEN);
+      HttpUtil.sendUnauthorized(response);
     }
   }
 
     }
     else
     {
-      permitted = PermissionUtil.hasPermission(repository, PermissionType.READ);
+      permitted = PermissionUtil.hasPermission(configuration, repository,
+        PermissionType.READ);
     }
 
     return permitted;

scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java

 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import sonia.scm.SCMContext;
 import sonia.scm.SCMContextProvider;
 import sonia.scm.ScmClientConfig;
 import sonia.scm.ScmState;
 
 //~--- JDK imports ------------------------------------------------------------
 
+import java.util.Collection;
+import java.util.Collections;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
   public Response getState(@Context HttpServletRequest request)
   {
     Response response = null;
-    ScmState state = null;
     Subject subject = SecurityUtils.getSubject();
 
     if (subject.isAuthenticated())
         logger.debug("return state for user {}", subject.getPrincipal());
       }
 
-      state = createState(subject);
+      ScmState state = createState(subject);
+
+      response = Response.ok(state).build();
+    }
+    else if (configuration.isAnonymousAccessEnabled())
+    {
+      User user = new User(SCMContext.USER_ANONYMOUS, "SCM Anonymous",
+                    "scm-anonymous@scm-manager.com");
+      ScmState state = createState(user, Collections.EMPTY_LIST);
+
       response = Response.ok(state).build();
     }
     else
     User user = collection.oneByType(User.class);
     GroupNames groups = collection.oneByType(GroupNames.class);
 
-    return new ScmState(contextProvider, user, groups.getCollection(),
+    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));
   }

scm-webapp/src/main/java/sonia/scm/filter/AdminSecurityFilter.java

 
 //~--- non-JDK imports --------------------------------------------------------
 
+import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
 import org.apache.shiro.subject.Subject;
 
+import sonia.scm.config.ScmConfiguration;
 import sonia.scm.security.Role;
 
 /**
 {
 
   /**
+   * Constructs ...
+   *
+   *
+   * @param configuration
+   */
+  @Inject
+  public AdminSecurityFilter(ScmConfiguration configuration)
+  {
+    super(configuration);
+  }
+
+  //~--- get methods ----------------------------------------------------------
+
+  /**
    * Method description
    *
    *

scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java

 
 //~--- non-JDK imports --------------------------------------------------------
 
+import com.google.inject.Inject;
 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;
   /** Field description */
   public static final String URL_AUTHENTICATION = "/api/rest/authentication";
 
+  //~--- constructors ---------------------------------------------------------
+
+  /**
+   * Constructs ...
+   *
+   *
+   * @param configuration
+   */
+  @Inject
+  public SecurityFilter(ScmConfiguration configuration)
+  {
+    this.configuration = configuration;
+  }
+
   //~--- methods --------------------------------------------------------------
 
   /**
       if (hasPermission(subject))
       {
         chain.doFilter(new SecurityHttpServletRequestWrapper(request,
-          subject.getPrincipals().oneByType(User.class)), response);
+          getUser(subject)), response);
       }
       else if (subject.isAuthenticated())
       {
    */
   protected boolean hasPermission(Subject subject)
   {
-    return subject.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 = new User(SCMContext.USER_ANONYMOUS, "SCM Anonymous",
+        "scm-anonymous@scm-manager.com");
+    }
+
+    return user;
+  }
+
+  //~--- fields ---------------------------------------------------------------
+
+  /** Field description */
+  private ScmConfiguration configuration;
 }

scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java

 import sonia.scm.SCMContextProvider;
 import sonia.scm.Type;
 import sonia.scm.config.ScmConfiguration;
-import sonia.scm.security.RepositoryPermission;
 import sonia.scm.security.ScmSecurityException;
 import sonia.scm.util.AssertUtil;
 import sonia.scm.util.CollectionAppender;
   {
     if (!SecurityUtils.getSubject().hasRole("admin"))
     {
-      throw new SecurityException("admin role is required");
+      throw new ScmSecurityException("admin role is required");
     }
   }
 
    */
   private boolean isPermitted(Repository repository, PermissionType type)
   {
-    return SecurityUtils.getSubject().isPermitted(
-      new RepositoryPermission(repository, PermissionType.READ));
+    return PermissionUtil.hasPermission(configuration, repository, type);
   }
 
   /**

scm-webapp/src/main/java/sonia/scm/web/security/ApiBasicAuthenticationFilter.java

 
 //~--- non-JDK imports --------------------------------------------------------
 
+import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
+import sonia.scm.config.ScmConfiguration;
 import sonia.scm.web.filter.BasicAuthenticationFilter;
 
 //~--- JDK imports ------------------------------------------------------------
   /** Field description */
   public static final String URI_STATE = "/api/rest/authentication/state";
 
+  //~--- constructors ---------------------------------------------------------
+
+  /**
+   * Constructs ...
+   *
+   *
+   * @param configuration
+   */
+  @Inject
+  public ApiBasicAuthenticationFilter(ScmConfiguration configuration)
+  {
+    super(configuration);
+  }
+
   //~--- methods --------------------------------------------------------------
 
   /**