diff --git a/scm-core/src/main/java/sonia/scm/security/ScmSecurityException.java b/scm-core/src/main/java/sonia/scm/security/ScmSecurityException.java new file mode 100644 index 0000000000..fa12a6ea5b --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/security/ScmSecurityException.java @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.security; + +/** + * + * @author Sebastian Sdorra + */ +public class ScmSecurityException extends RuntimeException +{ + + /** Field description */ + private static final long serialVersionUID = 3166977667869197399L; + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + */ + public ScmSecurityException() {} + + /** + * Constructs ... + * + * + * @param message + */ + public ScmSecurityException(String message) + { + super(message); + } + + /** + * Constructs ... + * + * + * @param throwable + */ + public ScmSecurityException(Throwable throwable) + { + super(throwable); + } + + /** + * Constructs ... + * + * + * @param message + * @param throwable + */ + public ScmSecurityException(String message, Throwable throwable) + { + super(message, throwable); + } +} diff --git a/scm-core/src/main/java/sonia/scm/user/xml/XmlUserManager.java b/scm-core/src/main/java/sonia/scm/user/xml/XmlUserManager.java index 0791d69f58..156b9bfaaf 100644 --- a/scm-core/src/main/java/sonia/scm/user/xml/XmlUserManager.java +++ b/scm-core/src/main/java/sonia/scm/user/xml/XmlUserManager.java @@ -35,17 +35,21 @@ package sonia.scm.user.xml; //~--- 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.SCMContextProvider; +import sonia.scm.security.SecurityContext; import sonia.scm.user.AbstractUserManager; import sonia.scm.user.User; import sonia.scm.user.UserAllreadyExistException; import sonia.scm.user.UserException; import sonia.scm.util.IOUtil; +import sonia.scm.util.SecurityUtil; import sonia.scm.util.Util; //~--- JDK imports ------------------------------------------------------------ @@ -81,6 +85,20 @@ public class XmlUserManager extends AbstractUserManager private static final Logger logger = LoggerFactory.getLogger(XmlUserManager.class); + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param scurityContextProvider + */ + @Inject + public XmlUserManager(Provider scurityContextProvider) + { + this.scurityContextProvider = scurityContextProvider; + } + //~--- methods -------------------------------------------------------------- /** @@ -108,6 +126,8 @@ public class XmlUserManager extends AbstractUserManager @Override public void create(User user) throws UserException, IOException { + SecurityUtil.assertIsAdmin(scurityContextProvider); + if (userDB.contains(user.getName())) { throw new UserAllreadyExistException(); @@ -139,6 +159,8 @@ public class XmlUserManager extends AbstractUserManager @Override public void delete(User user) throws UserException, IOException { + SecurityUtil.assertIsAdmin(scurityContextProvider); + String name = user.getName(); if (userDB.contains(name)) @@ -193,6 +215,8 @@ public class XmlUserManager extends AbstractUserManager @Override public void modify(User user) throws UserException, IOException { + SecurityUtil.assertIsAdmin(scurityContextProvider); + String name = user.getName(); if (userDB.contains(name)) @@ -222,6 +246,8 @@ public class XmlUserManager extends AbstractUserManager @Override public void refresh(User user) throws UserException, IOException { + SecurityUtil.assertIsAdmin(scurityContextProvider); + User fresh = userDB.get(user.getName()); if (fresh == null) @@ -245,6 +271,8 @@ public class XmlUserManager extends AbstractUserManager @Override public User get(String id) { + + // SecurityUtil.assertIsAdmin(scurityContextProvider); User user = userDB.get(id); if (user != null) @@ -264,6 +292,8 @@ public class XmlUserManager extends AbstractUserManager @Override public Collection getAll() { + SecurityUtil.assertIsAdmin(scurityContextProvider); + LinkedList users = new LinkedList(); for (User user : userDB.values()) @@ -322,6 +352,9 @@ public class XmlUserManager extends AbstractUserManager //~--- fields --------------------------------------------------------------- + /** Field description */ + private Provider scurityContextProvider; + /** Field description */ private XmlUserDatabase userDB; diff --git a/scm-core/src/main/java/sonia/scm/util/SecurityUtil.java b/scm-core/src/main/java/sonia/scm/util/SecurityUtil.java new file mode 100644 index 0000000000..e8ed04a1e6 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/util/SecurityUtil.java @@ -0,0 +1,84 @@ +/** + * 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.util; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.inject.Provider; + +import sonia.scm.security.ScmSecurityException; +import sonia.scm.security.SecurityContext; +import sonia.scm.user.User; + +/** + * + * @author Sebastian Sdorra + */ +public class SecurityUtil +{ + + /** + * Method description + * + * + * @param contextProvider + */ + public static void assertIsAdmin(Provider contextProvider) + { + assertIsAdmin(contextProvider.get()); + } + + /** + * Method description + * + * + * @param context + */ + public static void assertIsAdmin(SecurityContext context) + { + AssertUtil.assertIsNotNull(context); + + User user = context.getUser(); + + if (user == null) + { + throw new ScmSecurityException("user is not authenticated"); + } + + if (!user.isAdmin()) + { + throw new ScmSecurityException("admin account is required"); + } + } +} diff --git a/scm-core/src/test/java/sonia/scm/user/XmlUserManagerTest.java b/scm-core/src/test/java/sonia/scm/user/XmlUserManagerTest.java index 1ba0840daa..785a733fde 100644 --- a/scm-core/src/test/java/sonia/scm/user/XmlUserManagerTest.java +++ b/scm-core/src/test/java/sonia/scm/user/XmlUserManagerTest.java @@ -35,8 +35,13 @@ package sonia.scm.user; //~--- non-JDK imports -------------------------------------------------------- +import com.google.inject.Provider; + +import sonia.scm.security.SecurityContext; import sonia.scm.user.xml.XmlUserManager; +import static org.mockito.Mockito.*; + /** * * @author Sebastian Sdorra @@ -53,6 +58,18 @@ public class XmlUserManagerTest extends UserManagerTestBase @Override public UserManager createUserHandler() { - return new XmlUserManager(); + User admin = new User("scmadmin", "SCM Admin", "scmadmin@scm.org"); + + admin.setAdmin(true); + + SecurityContext context = mock(SecurityContext.class); + + when(context.getUser()).thenReturn(admin); + + Provider scp = mock(Provider.class); + + when(scp.get()).thenReturn(context); + + return new XmlUserManager(scp); } }