Sebastian Sdorra avatar Sebastian Sdorra committed 5bc8c30

start implementation of authentication and authorization

Comments (0)

Files changed (16)

scm-plugin-backend/pom.xml

       <version>1.1</version>
       <scope>provided</scope>
     </dependency>
+    
+    <!-- logging -->
+    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jcl-over-slf4j</artifactId>
+      <version>${slf4j.version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>log4j-over-slf4j</artifactId>
+      <version>${slf4j.version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <version>${logback.version}</version>
+    </dependency>
 
     <dependency>
       <groupId>org.freemarker</groupId>
     </dependency>
 
     <dependency>
-      <groupId>ch.qos.logback</groupId>
-      <artifactId>logback-classic</artifactId>
-      <version>${logback.version}</version>
-    </dependency>
-
-    <dependency>
       <groupId>rome</groupId>
       <artifactId>rome</artifactId>
       <version>1.0</version>

scm-plugin-backend/src/main/java/sonia/scm/plugin/AdminAccountConfiguration.java

+/**
+ * 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.plugin;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.common.base.Objects;
+
+import org.apache.shiro.authc.SaltedAuthenticationInfo;
+import org.apache.shiro.codec.Base64;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.SimplePrincipalCollection;
+import org.apache.shiro.util.ByteSource;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@XmlRootElement(name = "admin-account")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class AdminAccountConfiguration implements SaltedAuthenticationInfo
+{
+
+  /** Field description */
+  private static final long serialVersionUID = -8678832281151044462L;
+
+  //~--- constructors ---------------------------------------------------------
+
+  /**
+   * Constructs ...
+   *
+   */
+  public AdminAccountConfiguration() {}
+
+  /**
+   * Constructs ...
+   *
+   *
+   * @param username
+   * @param salt
+   * @param password
+   */
+  public AdminAccountConfiguration(String username, String salt,
+    String password)
+  {
+    this.username = username;
+    this.salt = salt;
+    this.password = password;
+  }
+
+  //~--- methods --------------------------------------------------------------
+
+  /**
+   * Method description
+   *
+   *
+   * @param obj
+   *
+   * @return
+   */
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (obj == null)
+    {
+      return false;
+    }
+
+    if (getClass() != obj.getClass())
+    {
+      return false;
+    }
+
+    final AdminAccountConfiguration other = (AdminAccountConfiguration) obj;
+
+    return Objects.equal(username, other.username)
+      && Objects.equal(salt, other.salt)
+      && Objects.equal(password, other.password);
+  }
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  @Override
+  public int hashCode()
+  {
+    return Objects.hashCode(username, salt, password);
+  }
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  @Override
+  public String toString()
+  {
+    //J-
+    return Objects.toStringHelper(this)
+                  .add("username", username)
+                  .add("salt", "xxx")
+                  .add("password", "xxx")
+                  .toString();
+    //J+
+  }
+
+  //~--- get methods ----------------------------------------------------------
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  @Override
+  public Object getCredentials()
+  {
+    return password;
+  }
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  @Override
+  public ByteSource getCredentialsSalt()
+  {
+    return ByteSource.Util.bytes(Base64.decode(salt));
+  }
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  public String getPassword()
+  {
+    return password;
+  }
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  @Override
+  public PrincipalCollection getPrincipals()
+  {
+
+    // TODO
+    return new SimplePrincipalCollection(username, "scm-backend");
+  }
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  public String getSalt()
+  {
+    return salt;
+  }
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  public String getUsername()
+  {
+    return username;
+  }
+
+  //~--- fields ---------------------------------------------------------------
+
+  /** Field description */
+  private String password;
+
+  /** Field description */
+  private String salt;
+
+  /** Field description */
+  private String username;
+}

scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendConfiguration.java

 
 import java.io.File;
 
-
 import java.util.Set;
 
 import javax.xml.bind.annotation.XmlAccessType;
    *
    * @return
    */
+  public AdminAccountConfiguration getAdminAccount()
+  {
+    return adminAccount;
+  }
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
   public Set<File> getDirectories()
   {
     return directories;
   //~--- fields ---------------------------------------------------------------
 
   /** Field description */
+  @XmlElement(name = "admin-account")
+  private AdminAccountConfiguration adminAccount;
+
+  /** Field description */
   @XmlElement(name = "directory")
   @XmlElementWrapper(name = "directories")
   private Set<File> directories;

scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendContextListener.java

 import com.google.inject.Injector;
 import com.google.inject.servlet.GuiceServletContextListener;
 
+import org.apache.shiro.guice.web.ShiroWebModule;
+
 import sonia.scm.plugin.scanner.PluginScannerScheduler;
+import sonia.scm.plugin.security.SecurityModule;
 
 //~--- JDK imports ------------------------------------------------------------
 
+import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
 
 /**
   @Override
   public void contextInitialized(ServletContextEvent servletContextEvent)
   {
+    this.servletContext = servletContextEvent.getServletContext();
     super.contextInitialized(servletContextEvent);
     scheduler = injector.getInstance(PluginScannerScheduler.class);
     scheduler.start();
   @Override
   protected Injector getInjector()
   {
-    injector = Guice.createInjector(new ScmBackendModule());
+    injector = Guice.createInjector(ShiroWebModule.guiceFilterModule(),
+      new SecurityModule(servletContext), new ScmBackendModule());
 
     return injector;
   }
 
   /** Field description */
   private PluginScannerScheduler scheduler;
+
+  /** Field description */
+  private ServletContext servletContext;
 }

scm-plugin-backend/src/main/java/sonia/scm/plugin/Roles.java

+/**
+ * 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.plugin;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class Roles
+{
+  public static final String ADMIN = "admin";
+}

scm-plugin-backend/src/main/java/sonia/scm/plugin/ScmBackendModule.java

 //~--- non-JDK imports --------------------------------------------------------
 
 import com.google.inject.multibindings.Multibinder;
-import com.google.inject.name.Names;
 import com.google.inject.servlet.ServletModule;
 
 import net.sf.ehcache.CacheManager;
 import sonia.scm.plugin.scanner.PluginScannerFactory;
 import sonia.scm.plugin.scanner.PluginScannerScheduler;
 import sonia.scm.plugin.scanner.TimerPluginScannerScheduler;
-import sonia.scm.util.Util;
 import sonia.scm.web.proxy.ProxyConfigurationProvider;
 import sonia.scm.web.proxy.ProxyServlet;
 

scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/AdminResource.java

+/**
+ * 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.plugin.rest;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.Inject;
+
+import sonia.scm.plugin.BackendConfiguration;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import com.sun.jersey.api.view.Viewable;
+
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Path("admin")
+public class AdminResource extends ViewableResource
+{
+
+  /** Field description */
+  private static final String PAGE_OVERVIEW = "/admin/index";
+
+  //~--- constructors ---------------------------------------------------------
+
+  /**
+   * Constructs ...
+   *
+   *
+   * @param context
+   * @param configuration
+   */
+  @Inject
+  public AdminResource(ServletContext context,
+    BackendConfiguration configuration)
+  {
+    super(context, configuration);
+  }
+
+  //~--- methods --------------------------------------------------------------
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  @GET
+  @Path("index.html")
+  @Produces(MediaType.TEXT_HTML)
+  public Viewable overview()
+  {
+    Map<String, Object> env = createVarMap("Administrator");
+
+    return new Viewable(PAGE_OVERVIEW, env);
+  }
+}

scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/ErrorResource.java

+/**
+ * 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.plugin.rest;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.Inject;
+
+import sonia.scm.plugin.BackendConfiguration;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import com.sun.jersey.api.view.Viewable;
+
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Path("error")
+public class ErrorResource extends ViewableResource
+{
+
+  /** Field description */
+  private static final String PAGE_UNAUTHORIZED = "/error/Unauthorized.html";
+
+  //~--- constructors ---------------------------------------------------------
+
+  /**
+   * Constructs ...
+   *
+   *
+   * @param context
+   * @param configuration
+   */
+  @Inject
+  public ErrorResource(ServletContext context,
+    BackendConfiguration configuration)
+  {
+    super(context, configuration);
+  }
+
+  //~--- methods --------------------------------------------------------------
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  @GET
+  @Path("unauthorized.html")
+  @Produces(MediaType.TEXT_HTML)
+  public Viewable unauthorized()
+  {
+    Map<String, Object> env = createVarMap("Unauthorized");
+
+    return new Viewable(PAGE_UNAUTHORIZED, env);
+  }
+}

scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/LoginResource.java

+/**
+ * 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.plugin.rest;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.Inject;
+
+import sonia.scm.plugin.BackendConfiguration;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import com.sun.jersey.api.view.Viewable;
+
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Path("/page/login.html")
+public class LoginResource extends ViewableResource
+{
+
+  /** Field description */
+  private static final String PAGE_LOGIN = "/login";
+
+  //~--- constructors ---------------------------------------------------------
+
+  /**
+   * Constructs ...
+   *
+   *
+   * @param context
+   * @param configuration
+   */
+  @Inject
+  public LoginResource(ServletContext context,
+    BackendConfiguration configuration)
+  {
+    super(context, configuration);
+  }
+
+  //~--- methods --------------------------------------------------------------
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  @POST
+  @Produces(MediaType.TEXT_HTML)
+  public Viewable loginFailed()
+  {
+    Map<String, Object> vars = createVarMap("Login");
+
+    vars.put("error", "Login failed");
+
+    return new Viewable(PAGE_LOGIN, vars);
+  }
+
+  //~--- get methods ----------------------------------------------------------
+
+  /**
+   * Method description
+   *
+   *
+   * @return
+   */
+  @GET
+  @Produces(MediaType.TEXT_HTML)
+  public Viewable getForm()
+  {
+    Map<String, Object> vars = createVarMap("Login");
+
+    return new Viewable(PAGE_LOGIN, vars);
+  }
+}

scm-plugin-backend/src/main/java/sonia/scm/plugin/security/DefaultAdminRealm.java

+/**
+ * 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.plugin.security;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Inject;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UnknownAccountException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authc.credential.CredentialsMatcher;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import sonia.scm.plugin.AdminAccountConfiguration;
+import sonia.scm.plugin.BackendConfiguration;
+import sonia.scm.plugin.Roles;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class DefaultAdminRealm extends AuthorizingRealm
+{
+
+  /** Field description */
+  public static final String NAME = "scm.backend";
+
+  /**
+   * the logger for ScmBackendRealm
+   */
+  private static final Logger logger =
+    LoggerFactory.getLogger(DefaultAdminRealm.class);
+
+  //~--- constructors ---------------------------------------------------------
+
+  /**
+   * Constructs ...
+   *
+   *
+   * @param configuration
+   * @param credentialsMatcher
+   */
+  @Inject
+  public DefaultAdminRealm(BackendConfiguration configuration,
+    CredentialsMatcher credentialsMatcher)
+  {
+    super(credentialsMatcher);
+    this.configuration = configuration;
+    setAuthenticationTokenClass(UsernamePasswordToken.class);
+  }
+
+  //~--- methods --------------------------------------------------------------
+
+  /**
+   * Method description
+   *
+   *
+   * @param token
+   *
+   * @return
+   *
+   * @throws AuthenticationException
+   */
+  @Override
+  protected AuthenticationInfo doGetAuthenticationInfo(
+    AuthenticationToken token)
+    throws AuthenticationException
+  {
+    Preconditions.checkNotNull(token);
+
+    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
+
+    String username = upToken.getUsername();
+
+    if (logger.isDebugEnabled())
+    {
+      logger.debug("start authentication for user {}", username);
+    }
+
+    AdminAccountConfiguration adminAccount = configuration.getAdminAccount();
+
+    if (!adminAccount.getUsername().equals(adminAccount.getUsername()))
+    {
+      throw new UnknownAccountException("unknown account ".concat(username));
+    }
+
+    return adminAccount;
+  }
+
+  /**
+   * Method description
+   *
+   *
+   * @param principals
+   *
+   * @return
+   */
+  @Override
+  protected AuthorizationInfo doGetAuthorizationInfo(
+    PrincipalCollection principals)
+  {
+    if (principals == null)
+    {
+      throw new AuthenticationException("principals should not be null");
+    }
+
+    return new SimpleAuthorizationInfo(ImmutableSet.of(Roles.ADMIN));
+  }
+
+  //~--- fields ---------------------------------------------------------------
+
+  /** Field description */
+  private BackendConfiguration configuration;
+}

scm-plugin-backend/src/main/java/sonia/scm/plugin/security/SecurityModule.java

+/**
+ * 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.plugin.security;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
+
+import org.apache.shiro.authc.credential.CredentialsMatcher;
+import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
+import org.apache.shiro.crypto.RandomNumberGenerator;
+import org.apache.shiro.crypto.SecureRandomNumberGenerator;
+import org.apache.shiro.crypto.hash.SimpleHash;
+import org.apache.shiro.guice.web.ShiroWebModule;
+import org.apache.shiro.util.ByteSource;
+
+import sonia.scm.plugin.Roles;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.servlet.ServletContext;
+
+import javax.swing.JOptionPane;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class SecurityModule extends ShiroWebModule
+{
+
+  /** Field description */
+  private static final String ATTRIBUTE_FAILURE = "shiroLoginFailure";
+
+  /** Field description */
+  private static final String HASH_ALGORITHM = "SHA-256";
+
+  /** Field description */
+  private static final int HASH_ITERATIONS = 1024;
+
+  /** Field description */
+  private static final String PAGE_LOGIN = "/page/login.html";
+
+  /** Field description */
+  private static final String PAGE_SUCCESS = "/admin/index.html";
+
+  /** Field description */
+  private static final String PAGE_UNAUTHORIZED = "/error/unauthorized.html";
+
+  /** Field description */
+  private static final String PARAM_PASSWORD = "password";
+
+  /** Field description */
+  private static final String PARAM_REMEMBERME = "rememberme";
+
+  /** Field description */
+  private static final String PARAM_USERNAME = "username";
+
+  /** Field description */
+  private static final String PATTERN_ADMIN = "/admin/**";
+
+  /** Field description */
+  private static final Named NAMED_USERNAMEPARAM =
+    Names.named("shiro.usernameParam");
+
+  /** Field description */
+  private static final Named NAMED_UNAUTHORIZEDURL =
+    Names.named("shiro.unauthorizedUrl");
+
+  /** Field description */
+  private static final Named NAMED_SUCCESSURL = Names.named("shiro.successUrl");
+
+  /** Field description */
+  private static final Named NAMED_REMEMBERMEPARAM =
+    Names.named("shiro.rememberMeParam");
+
+  /** Field description */
+  private static final Named NAMED_PASSWORDPARAM =
+    Names.named("shiro.passwordParam");
+
+  /** Field description */
+  private static final Named NAMED_LOGINURL = Names.named("shiro.loginUrl");
+
+  /** Field description */
+  private static final Named NAMED_FAILUREKEYATTRIBUTE =
+    Names.named("shiro.failureKeyAttribute");
+
+  //~--- constructors ---------------------------------------------------------
+
+  /**
+   * Constructs ...
+   *
+   *
+   * @param servletContext
+   */
+  public SecurityModule(ServletContext servletContext)
+  {
+    super(servletContext);
+  }
+
+  //~--- methods --------------------------------------------------------------
+
+  /**
+   * Method description
+   *
+   *
+   * @param args
+   */
+  public static void main(String[] args)
+  {
+    String value = JOptionPane.showInputDialog("Password");
+    RandomNumberGenerator rng = new SecureRandomNumberGenerator();
+    ByteSource salt = rng.nextBytes();
+    SimpleHash hash = new SimpleHash(HASH_ALGORITHM, value, salt,
+                        HASH_ITERATIONS);
+
+    System.out.append("Salt: ").println(salt.toBase64());
+    System.out.append("Hash: ").println(hash.toBase64());
+  }
+
+  /**
+   * Method description
+   *
+   */
+  @Override
+  protected void configureShiroWeb()
+  {
+    bindConstants();
+    bindCredentialsMatcher();
+
+    // bind realm
+    bindRealm().to(DefaultAdminRealm.class);
+
+    // add filters
+    addFilterChain(PAGE_LOGIN, AUTHC);
+    addFilterChain(PATTERN_ADMIN, AUTHC, config(ROLES, Roles.ADMIN));
+  }
+
+  /**
+   * Method description
+   *
+   */
+  private void bindConstants()
+  {
+    bindConstant().annotatedWith(NAMED_LOGINURL).to(PAGE_LOGIN);
+    bindConstant().annotatedWith(NAMED_USERNAMEPARAM).to(PARAM_USERNAME);
+    bindConstant().annotatedWith(NAMED_PASSWORDPARAM).to(PARAM_PASSWORD);
+    bindConstant().annotatedWith(NAMED_REMEMBERMEPARAM).to(PARAM_REMEMBERME);
+    bindConstant().annotatedWith(NAMED_SUCCESSURL).to(PAGE_SUCCESS);
+    bindConstant().annotatedWith(NAMED_UNAUTHORIZEDURL).to(PAGE_UNAUTHORIZED);
+    bindConstant().annotatedWith(NAMED_FAILUREKEYATTRIBUTE).to(
+      ATTRIBUTE_FAILURE);
+  }
+
+  /**
+   * Method description
+   *
+   */
+  private void bindCredentialsMatcher()
+  {
+    HashedCredentialsMatcher matcher =
+      new HashedCredentialsMatcher(HASH_ALGORITHM);
+
+    matcher.setHashIterations(HASH_ITERATIONS);
+    matcher.setStoredCredentialsHexEncoded(false);
+    bind(CredentialsMatcher.class).toInstance(matcher);
+  }
+}

scm-plugin-backend/src/main/resources/logback.xml

 
   <logger name="sonia.scm" level="DEBUG" />
   <logger name="sonia.scm.plugin.scanner.DefaultPluginScanner" level="INFO" />
+  
+  <!-- trace logging -->
+  <logger name="org.apache.shiro" level="INFO" />
 
   <root level="WARN">
     <appender-ref ref="STDOUT" />

scm-plugin-backend/src/main/webapp/WEB-INF/ftl/admin/index.html

+<#include "../template/header.html">
+
+<h2>Admin</h2>
+
+<#include "../template/footer.html">

scm-plugin-backend/src/main/webapp/WEB-INF/ftl/error/unauthorized.html

+<#include "../template/header.html">
+
+<h2>Unauthorized</h2>
+
+<#include "../template/footer.html">

scm-plugin-backend/src/main/webapp/WEB-INF/ftl/login.html

+<#include "template/header.html">
+
+<form method="POST" action="">
+
+  <table>
+    <tr>
+      <td>
+        <label for="username">Username</label> 
+      </td>
+      <td>
+        <input type="text" name="username">
+      </td>
+    </tr>
+        <tr>
+      <td>
+        <label for="password">Password</label>
+      </td>
+      <td>
+        <input type="password" name="password">
+      </td>
+    </tr>
+  </table>
+  
+  <input type="submit" value="Login">
+  
+</form>
+
+<#include "template/footer.html">

scm-plugin-backend/src/main/webapp/WEB-INF/ftl/template/header.html

                 <header class="entry-header">
                   <h1 class="entry-title">${title}</h1>
                 </header>
+                <#if error??>
+                  <div style="color: red">${error}</div>
+                </#if>
                 <div class="entry-content">
                   <!-- content begin -->
                   
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.