diff --git a/scm-core/src/main/java/sonia/scm/group/GroupNames.java b/scm-core/src/main/java/sonia/scm/group/GroupNames.java index 24d32972b6..3aae0c5c4c 100644 --- a/scm-core/src/main/java/sonia/scm/group/GroupNames.java +++ b/scm-core/src/main/java/sonia/scm/group/GroupNames.java @@ -73,18 +73,7 @@ public final class GroupNames implements Serializable, Iterable @SuppressWarnings("unchecked") public GroupNames() { - this.collection = Collections.EMPTY_LIST; - } - - /** - * Constructs ... - * - * - * @param collection - */ - public GroupNames(Collection collection) - { - this.collection = Collections.unmodifiableCollection(collection); + this(Collections.EMPTY_LIST); } /** @@ -96,7 +85,30 @@ public final class GroupNames implements Serializable, Iterable */ public GroupNames(String groupName, String... groupNames) { - this.collection = Lists.asList(groupName, groupNames); + this(Lists.asList(groupName, groupNames)); + } + + /** + * Constructs ... + * + * + * @param collection + */ + public GroupNames(Collection collection) + { + this(collection, false); + } + + /** + * Constructs ... + * + * + * @param collection + */ + public GroupNames(Collection collection, boolean external) + { + this.collection = Collections.unmodifiableCollection(collection); + this.external = external; } //~--- methods -------------------------------------------------------------- @@ -181,8 +193,13 @@ public final class GroupNames implements Serializable, Iterable return collection; } - //~--- fields --------------------------------------------------------------- + public boolean isExternal() { + return external; + } + //~--- fields --------------------------------------------------------------- /** Field description */ private final Collection collection; + + private final boolean external; } diff --git a/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java b/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java index 0e3c06e32d..b37ac4adc3 100644 --- a/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java +++ b/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java @@ -108,11 +108,26 @@ public final class SyncingRealmHelper { */ public AuthenticationInfo createAuthenticationInfo(String realm, User user, Collection groups) { + return this.createAuthenticationInfo(realm, user, groups, false); + } + + /** + * Create {@link AuthenticationInfo} from user and groups. + * + * + * @param realm name of the realm + * @param user authenticated user + * @param groups groups of the authenticated user + * + * @return authentication info + */ + public AuthenticationInfo createAuthenticationInfo(String realm, User user, + Collection groups, boolean externalGroups) { SimplePrincipalCollection collection = new SimplePrincipalCollection(); collection.add(user.getId(), realm); collection.add(user, realm); - collection.add(new GroupNames(groups), realm); + collection.add(new GroupNames(groups, externalGroups), realm); return new SimpleAuthenticationInfo(collection, user.getPassword()); } diff --git a/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java b/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java index 50bde53ae1..7579e7d829 100644 --- a/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java +++ b/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java @@ -53,10 +53,13 @@ import sonia.scm.web.security.PrivilegedAction; import java.io.IOException; +import static java.util.Collections.singletonList; import static org.hamcrest.Matchers.hasItem; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -113,7 +116,7 @@ public class SyncingRealmHelperTest { public void testCreateAuthenticationInfo() { User user = new User("tricia"); AuthenticationInfo authInfo = helper.createAuthenticationInfo("unit-test", - user, "heartOfGold"); + user, singletonList("heartOfGold")); assertNotNull(authInfo); assertEquals("tricia", authInfo.getPrincipals().getPrimaryPrincipal()); @@ -123,6 +126,27 @@ public class SyncingRealmHelperTest { GroupNames groups = authInfo.getPrincipals().oneByType(GroupNames.class); assertThat(groups, hasItem("heartOfGold")); + assertFalse(groups.isExternal()); + } + + /** + * Tests {@link SyncingRealmHelper#createAuthenticationInfo(String, User, String...)}. + */ + @Test + public void testCreateAuthenticationInfoWithExternalGroups() { + User user = new User("tricia"); + AuthenticationInfo authInfo = helper.createAuthenticationInfo("unit-test", + user, singletonList("heartOfGold"), true); + + assertNotNull(authInfo); + assertEquals("tricia", authInfo.getPrincipals().getPrimaryPrincipal()); + assertThat(authInfo.getPrincipals().getRealmNames(), hasItem("unit-test")); + assertEquals(user, authInfo.getPrincipals().oneByType(User.class)); + + GroupNames groups = authInfo.getPrincipals().oneByType(GroupNames.class); + + assertThat(groups, hasItem("heartOfGold")); + assertTrue(groups.isExternal()); } /** diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AuthenticationResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AuthenticationResource.java index 47918080ab..7984e6c473 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AuthenticationResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AuthenticationResource.java @@ -8,6 +8,7 @@ import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.group.GroupNames; import sonia.scm.security.*; import javax.servlet.http.HttpServletRequest; @@ -91,6 +92,11 @@ public class AuthenticationResource { tokenBuilder.scope(Scope.valueOf(authentication.getScope())); } + GroupNames groupNames = subject.getPrincipals().oneByType(GroupNames.class); + if (groupNames != null && groupNames.isExternal()) { + tokenBuilder.groups(groupNames.getCollection().toArray(new String[]{})); + } + AccessToken token = tokenBuilder.build(); if (authentication.isCookie()) {