diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml
index dd04bd385c..cc0ab9e5a2 100644
--- a/scm-plugin-backend/pom.xml
+++ b/scm-plugin-backend/pom.xml
@@ -32,6 +32,26 @@
1.1
provided
+
+
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${slf4j.version}
+
+
+
+ org.slf4j
+ log4j-over-slf4j
+ ${slf4j.version}
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+
org.freemarker
@@ -51,12 +71,6 @@
${jersey.version}
-
- ch.qos.logback
- logback-classic
- ${logback.version}
-
-
rome
rome
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/AdminAccountConfiguration.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/AdminAccountConfiguration.java
new file mode 100644
index 0000000000..8ad43824a0
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/AdminAccountConfiguration.java
@@ -0,0 +1,229 @@
+/**
+ * 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;
+}
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendConfiguration.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendConfiguration.java
index cc2538033f..d30b781433 100644
--- a/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendConfiguration.java
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendConfiguration.java
@@ -42,7 +42,6 @@ import sonia.scm.xml.XmlIntervalAdapter;
import java.io.File;
-
import java.util.Set;
import javax.xml.bind.annotation.XmlAccessType;
@@ -61,6 +60,17 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class BackendConfiguration
{
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public AdminAccountConfiguration getAdminAccount()
+ {
+ return adminAccount;
+ }
+
/**
* Method description
*
@@ -140,6 +150,10 @@ public class BackendConfiguration
//~--- fields ---------------------------------------------------------------
+ /** Field description */
+ @XmlElement(name = "admin-account")
+ private AdminAccountConfiguration adminAccount;
+
/** Field description */
@XmlElement(name = "directory")
@XmlElementWrapper(name = "directories")
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendContextListener.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendContextListener.java
index 05672e3380..efa88255f7 100644
--- a/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendContextListener.java
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendContextListener.java
@@ -39,10 +39,14 @@ import com.google.inject.Guice;
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;
/**
@@ -74,6 +78,7 @@ public class BackendContextListener extends GuiceServletContextListener
@Override
public void contextInitialized(ServletContextEvent servletContextEvent)
{
+ this.servletContext = servletContextEvent.getServletContext();
super.contextInitialized(servletContextEvent);
scheduler = injector.getInstance(PluginScannerScheduler.class);
scheduler.start();
@@ -90,7 +95,8 @@ public class BackendContextListener extends GuiceServletContextListener
@Override
protected Injector getInjector()
{
- injector = Guice.createInjector(new ScmBackendModule());
+ injector = Guice.createInjector(ShiroWebModule.guiceFilterModule(),
+ new SecurityModule(servletContext), new ScmBackendModule());
return injector;
}
@@ -102,4 +108,7 @@ public class BackendContextListener extends GuiceServletContextListener
/** Field description */
private PluginScannerScheduler scheduler;
+
+ /** Field description */
+ private ServletContext servletContext;
}
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/Roles.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/Roles.java
new file mode 100644
index 0000000000..fe37f8b681
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/Roles.java
@@ -0,0 +1,38 @@
+/**
+ * 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";
+}
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/ScmBackendModule.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/ScmBackendModule.java
index 4f3139271b..3e09ffbced 100644
--- a/scm-plugin-backend/src/main/java/sonia/scm/plugin/ScmBackendModule.java
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/ScmBackendModule.java
@@ -36,7 +36,6 @@ package sonia.scm.plugin;
//~--- 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;
@@ -51,7 +50,6 @@ import sonia.scm.plugin.scanner.DefaultPluginScannerFactory;
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;
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/AdminResource.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/AdminResource.java
new file mode 100644
index 0000000000..8be0a12453
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/AdminResource.java
@@ -0,0 +1,97 @@
+/**
+ * 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 env = createVarMap("Administrator");
+
+ return new Viewable(PAGE_OVERVIEW, env);
+ }
+}
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/ErrorResource.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/ErrorResource.java
new file mode 100644
index 0000000000..0d415e8323
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/ErrorResource.java
@@ -0,0 +1,97 @@
+/**
+ * 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 env = createVarMap("Unauthorized");
+
+ return new Viewable(PAGE_UNAUTHORIZED, env);
+ }
+}
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/LoginResource.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/LoginResource.java
new file mode 100644
index 0000000000..00c4897814
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/LoginResource.java
@@ -0,0 +1,116 @@
+/**
+ * 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 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 vars = createVarMap("Login");
+
+ return new Viewable(PAGE_LOGIN, vars);
+ }
+}
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/security/DefaultAdminRealm.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/security/DefaultAdminRealm.java
new file mode 100644
index 0000000000..2d2f7e8fb7
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/security/DefaultAdminRealm.java
@@ -0,0 +1,154 @@
+/**
+ * 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;
+}
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/security/SecurityModule.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/security/SecurityModule.java
new file mode 100644
index 0000000000..de32606898
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/security/SecurityModule.java
@@ -0,0 +1,198 @@
+/**
+ * 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);
+ }
+}
diff --git a/scm-plugin-backend/src/main/resources/logback.xml b/scm-plugin-backend/src/main/resources/logback.xml
index 9f6c714a38..aba83a8d17 100644
--- a/scm-plugin-backend/src/main/resources/logback.xml
+++ b/scm-plugin-backend/src/main/resources/logback.xml
@@ -52,6 +52,9 @@
+
+
+
diff --git a/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/admin/index.html b/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/admin/index.html
new file mode 100644
index 0000000000..9ba191266f
--- /dev/null
+++ b/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/admin/index.html
@@ -0,0 +1,5 @@
+<#include "../template/header.html">
+
+Admin
+
+<#include "../template/footer.html">
\ No newline at end of file
diff --git a/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/error/unauthorized.html b/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/error/unauthorized.html
new file mode 100644
index 0000000000..7f989ea5b1
--- /dev/null
+++ b/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/error/unauthorized.html
@@ -0,0 +1,5 @@
+<#include "../template/header.html">
+
+Unauthorized
+
+<#include "../template/footer.html">
\ No newline at end of file
diff --git a/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/login.html b/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/login.html
new file mode 100644
index 0000000000..a3524202d0
--- /dev/null
+++ b/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/login.html
@@ -0,0 +1,28 @@
+<#include "template/header.html">
+
+
+
+<#include "template/footer.html">
\ No newline at end of file
diff --git a/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/template/header.html b/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/template/header.html
index 4ed6e881af..1928caf9ec 100644
--- a/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/template/header.html
+++ b/scm-plugin-backend/src/main/webapp/WEB-INF/ftl/template/header.html
@@ -113,6 +113,9 @@
+ <#if error??>
+ ${error}
+ #if>