Skip to content

Commit

Permalink
Implement new invitations API
Browse files Browse the repository at this point in the history
https://www.pivotaltracker.com/story/show/102277582 [#102277582]
Remove /new and /new.do UI endpoints. (return 404)
Users must be mapped to a single IDP
Remove ExpiringCodeService
Return user ids and proper error messages during invitations

The property IdentityProvider.config.emailDomain is a list of domain names.
Null or empty list means no invitations accepted (default) except for UAA domain
  • Loading branch information
Paul Warren authored and fhanik committed Sep 25, 2015
1 parent f765c05 commit 6e059f8
Show file tree
Hide file tree
Showing 37 changed files with 1,028 additions and 881 deletions.
Expand Up @@ -28,8 +28,6 @@ public class Origin {
public static final String KEYSTONE = "keystone";
public static final String SAML = "saml";
public static final String NotANumber = "NaN";
public static final String UNKNOWN = "unknown";


public static String getUserId(Authentication authentication) {
String id;
Expand Down
Expand Up @@ -17,7 +17,6 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.authentication.Origin;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
Expand Down Expand Up @@ -138,8 +137,8 @@ protected boolean isInvite() {
Authentication a = SecurityContextHolder.getContext().getAuthentication();
return (
a != null &&
a.getPrincipal() instanceof UaaPrincipal &&
Origin.UNKNOWN.equals(((UaaPrincipal)a.getPrincipal()).getOrigin())
a.getAuthorities().contains(UaaAuthority.UAA_INVITED) &&
a.getPrincipal() instanceof UaaPrincipal
);
}

Expand Down Expand Up @@ -216,4 +215,4 @@ public void setBeanName(String name) {
this.name = name;
}

}
}
Expand Up @@ -13,8 +13,6 @@
package org.cloudfoundry.identity.uaa.login.saml;


import java.util.Date;

import org.cloudfoundry.identity.uaa.authentication.Origin;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
Expand Down Expand Up @@ -43,6 +41,8 @@
import org.springframework.security.saml.SAMLAuthenticationToken;
import org.springframework.security.saml.context.SAMLMessageContext;

import java.util.Date;

public class LoginSamlAuthenticationProvider extends SAMLAuthenticationProvider implements ApplicationEventPublisherAware {

private UaaUserDatabase userDatabase;
Expand Down Expand Up @@ -93,6 +93,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
UaaPrincipal samlPrincipal = new UaaPrincipal(Origin.NotANumber, result.getName(), result.getName(), alias, result.getName(), zone.getId());
UaaPrincipal existingPrincipal =
SecurityContextHolder.getContext().getAuthentication()!=null &&
SecurityContextHolder.getContext().getAuthentication().getAuthorities().contains(UaaAuthority.UAA_INVITED) &&
SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UaaPrincipal ?
(UaaPrincipal)SecurityContextHolder.getContext().getAuthentication().getPrincipal() : null;

Expand All @@ -111,17 +112,13 @@ protected void publish(ApplicationEvent event) {
}

protected UaaPrincipal evaluateInvitiationPrincipal(UaaPrincipal samlPrincipal, UaaPrincipal existingPrincipal) {
if (existingPrincipal ==null) {
if (existingPrincipal == null) {
//no active invitation
return samlPrincipal;
} else if (Origin.UNKNOWN.equals(existingPrincipal.getOrigin())) {
//it is an invitation
if (!samlPrincipal.getEmail().equalsIgnoreCase(existingPrincipal.getEmail())) {
throw new BadCredentialsException("SAML User email mismatch. Authenticated email doesn't match invited email.");
}
return existingPrincipal;
} else if (!samlPrincipal.getEmail().equalsIgnoreCase(existingPrincipal.getEmail())) {
throw new BadCredentialsException("SAML User email mismatch. Authenticated email doesn't match invited email.");
} else {
return samlPrincipal;
return existingPrincipal;
}
}

Expand Down
Expand Up @@ -12,15 +12,6 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.oauth.token;

import java.lang.reflect.Field;
import java.math.BigInteger;
import java.security.Principal;
import java.security.interfaces.RSAPublicKey;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
Expand All @@ -35,6 +26,14 @@
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.reflect.Field;
import java.security.Principal;
import java.security.interfaces.RSAPublicKey;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
* OAuth2 token services that produces JWT encoded token values.
*
Expand Down
Expand Up @@ -32,7 +32,7 @@
*/
public enum UaaAuthority implements GrantedAuthority {

UAA_ADMIN("uaa.admin", 1), UAA_USER("uaa.user", 0), UAA_NONE("uaa.none", -1);
UAA_INVITED("uaa.invited", 1), UAA_ADMIN("uaa.admin", 1), UAA_USER("uaa.user", 0), UAA_NONE("uaa.none", -1);

public static final List<UaaAuthority> ADMIN_AUTHORITIES = Collections.unmodifiableList(Arrays.asList(UAA_ADMIN,
UAA_USER));
Expand Down
Expand Up @@ -15,21 +15,24 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.AbstractIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.authentication.Origin;
import org.cloudfoundry.identity.uaa.client.ClientConstants;
import org.cloudfoundry.identity.uaa.ldap.LdapIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.login.saml.SamlIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.zone.IdentityProvider;
import org.cloudfoundry.identity.uaa.zone.IdentityZone;
import org.cloudfoundry.identity.uaa.zone.UaaIdentityProviderDefinition;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.util.Collections.EMPTY_LIST;
import static org.cloudfoundry.identity.uaa.authentication.Origin.LDAP;
import static org.cloudfoundry.identity.uaa.authentication.Origin.SAML;
import static org.cloudfoundry.identity.uaa.authentication.Origin.UAA;

public class DomainFilter {

Expand Down Expand Up @@ -82,19 +85,19 @@ protected List<String> getEmailDomain(IdentityProvider provider) {
AbstractIdentityProviderDefinition definition = null;
if (provider.getConfig()!=null) {
switch (provider.getType()) {
case Origin.UAA: {
case UAA: {
definition = provider.getConfigValue(UaaIdentityProviderDefinition.class);
break;
}
case Origin.LDAP: {
case LDAP: {
try {
definition = provider.getConfigValue(LdapIdentityProviderDefinition.class);
} catch (JsonUtils.JsonUtilException x) {
logger.error("Unable to parse LDAP configuration:"+provider.getConfig());
}
break;
}
case Origin.SAML: {
case SAML: {
definition = provider.getConfigValue(SamlIdentityProviderDefinition.class);
break;
}
Expand All @@ -112,10 +115,21 @@ protected List<String> getEmailDomain(IdentityProvider provider) {

protected boolean doesEmailDomainMatchProvider(IdentityProvider provider, String domain, boolean explicit) {
List<String> domainList = getEmailDomain(provider);
if (explicit && Origin.UAA.equals(provider.getOriginKey())) {
return domainList == null ? false : domainList.contains(domain);
List<String> wildcardList;
if (explicit) {
wildcardList = domainList;
} else {
return domainList == null ? true : domainList.contains(domain);
if (UAA.equals(provider.getOriginKey())) {
wildcardList = domainList == null ? Arrays.asList("*.*", "*.*.*", "*.*.*.*") : domainList;
} else {
wildcardList = domainList == null ? null : domainList;
}
}
if (wildcardList==null) {
return false;
} else {
Set<Pattern> patterns = UaaStringUtils.constructWildcards(wildcardList);
return UaaStringUtils.matches(patterns, domain);
}
}

Expand Down
Expand Up @@ -19,6 +19,7 @@
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Map;


public class JsonUtils {
Expand Down
Expand Up @@ -14,9 +14,7 @@

package org.cloudfoundry.identity.uaa.util;

import org.cloudfoundry.identity.uaa.AbstractIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.authentication.Origin;
import org.cloudfoundry.identity.uaa.client.ClientConstants;
import org.cloudfoundry.identity.uaa.ldap.LdapIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.login.saml.SamlIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.zone.IdentityProvider;
Expand All @@ -25,17 +23,17 @@
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static java.util.Collections.EMPTY_LIST;
import static org.cloudfoundry.identity.uaa.authentication.Origin.LOGIN_SERVER;
import static org.cloudfoundry.identity.uaa.client.ClientConstants.ALLOWED_PROVIDERS;
import static org.junit.Assert.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

public class DomainFilterTest {

Expand Down Expand Up @@ -78,6 +76,7 @@ public class DomainFilterTest {
IdentityProvider ldapProvider;
IdentityProvider samlProvider1;
IdentityProvider samlProvider2;
IdentityProvider loginServerProvider;

DomainFilter filter = new DomainFilter();

Expand All @@ -90,7 +89,6 @@ public class DomainFilterTest {
@Before
public void setUp() throws Exception {
client = new BaseClientDetails("clientid","", "", "","","");

uaaDef = new UaaIdentityProviderDefinition(null, null);
ldapDef = new LdapIdentityProviderDefinition();
samlDef1 = new SamlIdentityProviderDefinition(idpMetaData,"","",0,true,true,"","", IdentityZone.getUaa().getId());
Expand All @@ -103,7 +101,8 @@ private void configureTestData() {
ldapProvider = new IdentityProvider().setActive(true).setType(Origin.LDAP).setOriginKey(Origin.LDAP).setConfig(JsonUtils.writeValueAsString(ldapDef));
samlProvider1 = new IdentityProvider().setActive(true).setType(Origin.SAML).setOriginKey("saml1").setConfig(JsonUtils.writeValueAsString(samlDef1));
samlProvider2 = new IdentityProvider().setActive(true).setType(Origin.SAML).setOriginKey("saml2").setConfig(JsonUtils.writeValueAsString(samlDef2));
activeProviders = Arrays.asList(uaaProvider, ldapProvider, samlProvider1, samlProvider2);
loginServerProvider = new IdentityProvider().setActive(true).setType(LOGIN_SERVER).setOriginKey(LOGIN_SERVER);
activeProviders = Arrays.asList(uaaProvider, ldapProvider, samlProvider1, samlProvider2, loginServerProvider);
}

@Test
Expand All @@ -114,16 +113,17 @@ public void test_null_arguments() throws Exception {
assertThat(filter.filter(null,client,email), Matchers.containsInAnyOrder());
assertThat(filter.filter(activeProviders,null,null), Matchers.containsInAnyOrder());
assertThat(filter.filter(activeProviders,client,null), Matchers.containsInAnyOrder());
assertThat(filter.filter(activeProviders,client,email), Matchers.containsInAnyOrder(uaaProvider));
}

@Test
public void test_default_idp_and_client_setup() {
assertThat(filter.filter(activeProviders,null,email), Matchers.containsInAnyOrder(ldapProvider, samlProvider1, samlProvider2));
assertThat(filter.filter(activeProviders,client,email), Matchers.containsInAnyOrder(ldapProvider, samlProvider1, samlProvider2));
assertThat(filter.filter(Arrays.asList(ldapProvider),null,email), Matchers.containsInAnyOrder(ldapProvider));
assertThat(filter.filter(Arrays.asList(ldapProvider),client,email), Matchers.containsInAnyOrder(ldapProvider));
assertThat(filter.filter(Arrays.asList(uaaProvider, samlProvider2),null,email), Matchers.containsInAnyOrder(samlProvider2));
assertThat(filter.filter(Arrays.asList(uaaProvider, samlProvider2),client,email), Matchers.containsInAnyOrder(samlProvider2));
assertThat(filter.filter(activeProviders,null,email), Matchers.containsInAnyOrder(uaaProvider));
assertThat(filter.filter(activeProviders,client,email), Matchers.containsInAnyOrder(uaaProvider));
assertThat(filter.filter(Arrays.asList(ldapProvider),null,email), Matchers.containsInAnyOrder());
assertThat(filter.filter(Arrays.asList(ldapProvider),client,email), Matchers.containsInAnyOrder());
assertThat(filter.filter(Arrays.asList(uaaProvider, samlProvider2),null,email), Matchers.containsInAnyOrder(uaaProvider));
assertThat(filter.filter(Arrays.asList(uaaProvider, samlProvider2),client,email), Matchers.containsInAnyOrder(uaaProvider));
assertThat(filter.filter(Arrays.asList(uaaProvider), null, email), Matchers.containsInAnyOrder(uaaProvider));
assertThat(filter.filter(Arrays.asList(uaaProvider),client,email), Matchers.containsInAnyOrder(uaaProvider));
}
Expand All @@ -142,6 +142,7 @@ public void test_single_positive_email_domain_match() {
ldapDef.setEmailDomain(Arrays.asList("test.org"));
configureTestData();
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(ldapProvider));
assertThat(filter.filter(activeProviders, client, "some@other.domain"), Matchers.containsInAnyOrder(uaaProvider));
}

@Test
Expand All @@ -154,6 +155,26 @@ public void test_multiple_positive_email_domain_matches() {
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(ldapProvider, samlProvider2));
}

@Test
public void test_multiple_positive_email_domain_matches_wildcard() {
uaaDef.setEmailDomain(null);
samlDef1.setEmailDomain(EMPTY_LIST);
samlDef2.setEmailDomain(Arrays.asList("*.org"));
ldapDef.setEmailDomain(Arrays.asList("*.org"));
configureTestData();
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(ldapProvider, samlProvider2));
}

@Test
public void test_multiple_positive_long_email_domain_matches_wildcard() {
uaaDef.setEmailDomain(null);
samlDef1.setEmailDomain(EMPTY_LIST);
samlDef2.setEmailDomain(Arrays.asList("*.*.*.com"));
ldapDef.setEmailDomain(Arrays.asList("*.*.test2.com"));
configureTestData();
assertThat(filter.filter(activeProviders, client, "user@test.test1.test2.com"), Matchers.containsInAnyOrder(ldapProvider, samlProvider2));
}

@Test
public void test_multiple_positive_email_domain_matches_single_client_allowed_provider() {
uaaDef.setEmailDomain(null);
Expand All @@ -176,16 +197,26 @@ public void test_multiple_positive_email_domain_matches_single_client_allowed_pr
@Test
public void test_single_client_allowed_provider() {
client.addAdditionalInformation(ALLOWED_PROVIDERS, Arrays.asList(ldapProvider.getOriginKey()));
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder());

ldapDef.setEmailDomain(Arrays.asList("test.org"));
configureTestData();
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(ldapProvider));
}

@Test
public void test_multiple_client_allowed_providers() {
client.addAdditionalInformation(ALLOWED_PROVIDERS, Arrays.asList(ldapProvider.getOriginKey(), uaaProvider.getOriginKey()));
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(ldapProvider));
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(uaaProvider));

client.addAdditionalInformation(ALLOWED_PROVIDERS, Arrays.asList(ldapProvider.getOriginKey(), samlProvider2.getOriginKey()));
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(ldapProvider, samlProvider2));
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder());

ldapDef.setEmailDomain(Arrays.asList("test.org"));
configureTestData();
client.addAdditionalInformation(ALLOWED_PROVIDERS, Arrays.asList(ldapProvider.getOriginKey(), uaaProvider.getOriginKey()));
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(ldapProvider));

}

@Test
Expand All @@ -197,13 +228,22 @@ public void test_uaa_is_catch_all() {
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(uaaProvider));
}

@Test
public void test_uaa_is_catch_all_with_null_email_domain_list() {
ldapDef.setEmailDomain(null);
samlDef1.setEmailDomain(null);
samlDef2.setEmailDomain(null);
configureTestData();
assertThat(filter.filter(activeProviders, client, email), Matchers.containsInAnyOrder(uaaProvider));
}

@Test
public void test_domain_filter_match() {
assertFalse(filter.doesEmailDomainMatchProvider(uaaProvider, "test.org", true));
assertTrue(filter.doesEmailDomainMatchProvider(uaaProvider, "test.org", false));
assertTrue(filter.doesEmailDomainMatchProvider(ldapProvider, "test.org", false));
assertTrue(filter.doesEmailDomainMatchProvider(ldapProvider, "test.org", true));
assertTrue(filter.doesEmailDomainMatchProvider(samlProvider1, "test.org", false));
assertTrue(filter.doesEmailDomainMatchProvider(samlProvider1, "test.org", true));
assertFalse(filter.doesEmailDomainMatchProvider(ldapProvider, "test.org", false));
assertFalse(filter.doesEmailDomainMatchProvider(ldapProvider, "test.org", true));
assertFalse(filter.doesEmailDomainMatchProvider(samlProvider1, "test.org", false));
assertFalse(filter.doesEmailDomainMatchProvider(samlProvider1, "test.org", true));
}
}
Expand Up @@ -92,6 +92,7 @@ public void testContainsWildCard() {
assertTrue(UaaStringUtils.containsWildcard("space.*"));
assertFalse(UaaStringUtils.containsWildcard("space.developer"));
assertTrue(UaaStringUtils.containsWildcard("space.*.*.developer"));
assertTrue(UaaStringUtils.containsWildcard("*"));
}

@Test
Expand Down

0 comments on commit 6e059f8

Please sign in to comment.