Skip to content

Commit

Permalink
finish MFA provider POST implementation
Browse files Browse the repository at this point in the history
[#150620737] https://www.pivotaltracker.com/story/show/150620737
Signed-off-by: Shash Reddy <sreddy@pivotal.io>
  • Loading branch information
6palace authored and cf-identity committed Sep 27, 2017
1 parent fcb53c7 commit bbf6a19
Show file tree
Hide file tree
Showing 15 changed files with 406 additions and 46 deletions.
Expand Up @@ -26,4 +26,18 @@ public T setIssuer(String issuer) {
return (T) this; return (T) this;
} }


@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

AbstractMfaProviderConfig<?> that = (AbstractMfaProviderConfig<?>) o;

return issuer != null ? issuer.equals(that.issuer) : that.issuer == null;
}

@Override
public int hashCode() {
return issuer != null ? issuer.hashCode() : 0;
}
} }
@@ -1,10 +1,6 @@
package org.cloudfoundry.identity.uaa.mfa_provider; package org.cloudfoundry.identity.uaa.mfa_provider;




import org.springframework.util.StringUtils;

import static org.springframework.util.StringUtils.hasText;

public class GoogleMfaProviderConfig extends AbstractMfaProviderConfig<GoogleMfaProviderConfig> { public class GoogleMfaProviderConfig extends AbstractMfaProviderConfig<GoogleMfaProviderConfig> {


public enum Algorithm { SHA256, SHA512 } public enum Algorithm { SHA256, SHA512 }
Expand Down Expand Up @@ -52,4 +48,29 @@ public GoogleMfaProviderConfig setAlgorithm(Algorithm algorithm) {
this.algorithm = algorithm; this.algorithm = algorithm;
return this; return this;
} }

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

GoogleMfaProviderConfig that = (GoogleMfaProviderConfig) o;

if (digits != that.digits) return false;
if (duration != that.duration) return false;
if (providerDescription != null ? !providerDescription.equals(that.providerDescription) : that.providerDescription != null)
return false;
if(algorithm != that.algorithm) return false;
return super.equals(that);
}

@Override
public int hashCode() {
int result = super.hashCode();
result += providerDescription != null ? providerDescription.hashCode() : 0;
result = 31 * result + digits;
result = 31 * result + duration;
result = 31 * result + (algorithm != null ? algorithm.hashCode() : 0);
return result;
}
} }
@@ -1,66 +1,113 @@
package org.cloudfoundry.identity.uaa.mfa_provider; package org.cloudfoundry.identity.uaa.mfa_provider;


import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import org.cloudfoundry.identity.uaa.provider.AbstractIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.KeystoneIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.LdapIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.OIDCIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.RawXOAuthIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.SamlIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.UaaIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.util.JsonUtils; import org.cloudfoundry.identity.uaa.util.JsonUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;


import javax.xml.bind.ValidationException;

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


import static org.cloudfoundry.identity.uaa.constants.OriginKeys.KEYSTONE;
import static org.cloudfoundry.identity.uaa.constants.OriginKeys.LDAP;
import static org.cloudfoundry.identity.uaa.constants.OriginKeys.OAUTH20;
import static org.cloudfoundry.identity.uaa.constants.OriginKeys.OIDC10;
import static org.cloudfoundry.identity.uaa.constants.OriginKeys.SAML;
import static org.cloudfoundry.identity.uaa.constants.OriginKeys.UAA;
import static org.cloudfoundry.identity.uaa.constants.OriginKeys.UNKNOWN;
import static org.cloudfoundry.identity.uaa.util.JsonUtils.getNodeAsBoolean; import static org.cloudfoundry.identity.uaa.util.JsonUtils.getNodeAsBoolean;
import static org.cloudfoundry.identity.uaa.util.JsonUtils.getNodeAsDate;
import static org.cloudfoundry.identity.uaa.util.JsonUtils.getNodeAsString; import static org.cloudfoundry.identity.uaa.util.JsonUtils.getNodeAsString;
import static org.cloudfoundry.identity.uaa.util.JsonUtils.readValue;


@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(using = MfaProvider.MfaProviderDeserializer.class) @JsonDeserialize(using = MfaProvider.MfaProviderDeserializer.class)
public class MfaProvider<T extends AbstractMfaProviderConfig> { public class MfaProvider<T extends AbstractMfaProviderConfig> {


public static final String FIELD_IDENTITY_ZONE_ID = "identityZoneId";
public static final String FIELD_TYPE = "type"; public static final String FIELD_TYPE = "type";
public static final String FIELD_NAME = "name"; public static final String FIELD_NAME = "name";
public static final String FIELD_ACTIVE = "active"; public static final String FIELD_ACTIVE = "active";
public static final String FIELD_CREATED = "created";
public static final String FIELD_LAST_MODIFIED = "last_modified";
public static final String FIELD_ID = "id"; public static final String FIELD_ID = "id";






private String id; private String id;
private String name; private String name;
private String identityZoneId;
private boolean active = true; private boolean active = true;

private AbstractMfaProviderConfig config; private AbstractMfaProviderConfig config;

private MfaProviderType type; private MfaProviderType type;
private Date created;
@JsonProperty("last_modified")
private Date lastModified;


enum MfaProviderType {
GOOGLE_AUTHENTICATOR public Date getCreated() {
return created;
} }


public AbstractMfaProviderConfig getConfig() { public MfaProvider<T> setCreated(Date created) {
return config; this.created = created;
return this;
} }


public MfaProvider setConfig(T config) { public Date getLastModified() {
return lastModified;
}

public MfaProvider<T> setLastModified(Date lastModified) {
this.lastModified = lastModified;
return this;
}


public String getIdentityZoneId() {
return identityZoneId;
}

public MfaProvider<T> setIdentityZoneId(String identityZoneId) {
this.identityZoneId = identityZoneId;
return this;
}

public enum MfaProviderType {
GOOGLE_AUTHENTICATOR;

private static Map<String, MfaProviderType> namesMap = new HashMap<String, MfaProviderType>();
static {
namesMap.put("google-authenticator", GOOGLE_AUTHENTICATOR);
}

@JsonCreator
public static MfaProviderType forValue(String value) {
return namesMap.get(value);
}

@JsonValue
public String toValue() {
for (Map.Entry<String, MfaProviderType> entry : namesMap.entrySet()) {
if (entry.getValue() == this)
return entry.getKey();
}

return null; // or fail
}
}

public T getConfig() {
return (T) config;
}

public MfaProvider<T> setConfig(T config) {
this.config = config; this.config = config;
return this; return this;
} }
Expand All @@ -69,11 +116,12 @@ public String getId() {
return id; return id;
} }


public void setId(String id) { public MfaProvider<T> setId(String id) {
this.id = id; this.id = id;
return this;
} }


public Boolean getActive() { public Boolean isActive() {
return active; return active;
} }


Expand All @@ -86,7 +134,7 @@ public String getName() {
return name; return name;
} }


public MfaProvider setName(String name) { public MfaProvider<T> setName(String name) {
this.name = name; this.name = name;
return this; return this;
} }
Expand All @@ -95,7 +143,7 @@ public MfaProviderType getType() {
return type; return type;
} }


public MfaProvider setType(MfaProviderType type) { public MfaProvider<T> setType(MfaProviderType type) {
this.type = type; this.type = type;
return this; return this;
} }
Expand All @@ -113,6 +161,9 @@ public void validate() {
if(config == null) { if(config == null) {
throw new IllegalArgumentException("Provider config must be set"); throw new IllegalArgumentException("Provider config must be set");
} }
if(!StringUtils.hasText(identityZoneId)){
throw new IllegalArgumentException("Provider must belong to a zone");
}
config.validate(); config.validate();
} }


Expand All @@ -125,7 +176,7 @@ public MfaProvider deserialize(JsonParser p, DeserializationContext ctxt) throws
JsonNode node = JsonUtils.readTree(p); JsonNode node = JsonUtils.readTree(p);
MfaProviderType type; MfaProviderType type;
try { try {
type = MfaProviderType.valueOf(getNodeAsString(node, FIELD_TYPE, MfaProviderType.GOOGLE_AUTHENTICATOR.name())); type = MfaProviderType.forValue(getNodeAsString(node, FIELD_TYPE, "google-authenticator"));
} catch(IllegalArgumentException e) { } catch(IllegalArgumentException e) {
type = null; type = null;
} }
Expand All @@ -148,9 +199,9 @@ public MfaProvider deserialize(JsonParser p, DeserializationContext ctxt) throws
result.setName(getNodeAsString(node, FIELD_NAME, null)); result.setName(getNodeAsString(node, FIELD_NAME, null));
result.setId(getNodeAsString(node, FIELD_ID, null)); result.setId(getNodeAsString(node, FIELD_ID, null));
result.setActive(getNodeAsBoolean(node, FIELD_ACTIVE, true)); result.setActive(getNodeAsBoolean(node, FIELD_ACTIVE, true));

result.setIdentityZoneId(getNodeAsString(node, FIELD_IDENTITY_ZONE_ID, null));

result.setCreated(getNodeAsDate(node, FIELD_CREATED));

result.setLastModified(getNodeAsDate(node, FIELD_LAST_MODIFIED));


return result; return result;
} }
Expand Down
@@ -1,19 +1,70 @@
package org.cloudfoundry.identity.uaa.mfa_provider; package org.cloudfoundry.identity.uaa.mfa_provider;


import com.fasterxml.jackson.databind.JsonNode;
import org.cloudfoundry.identity.uaa.util.JsonUtils;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;


import javax.xml.bind.ValidationException; import javax.xml.bind.ValidationException;


import java.util.Date;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;


public class MfaProviderTest { public class MfaProviderTest {


@Rule @Rule
public ExpectedException expectedException = ExpectedException.none(); public ExpectedException expectedException = ExpectedException.none();


@Test
public void testSerialize() {

MfaProvider<GoogleMfaProviderConfig> provider = createValidGoogleMfaProvider();
provider.setCreated(new Date());
provider.setLastModified(new Date());
String string = JsonUtils.writeValueAsString(provider);
JsonNode output = JsonUtils.readTree(JsonUtils.writeValueAsString(provider));
assertEquals(output.get("type").textValue(), MfaProvider.MfaProviderType.GOOGLE_AUTHENTICATOR.toValue());
JsonNode config = output.get("config");
assertEquals(config.get("algorithm").textValue(), GoogleMfaProviderConfig.Algorithm.SHA256.toString());
assertEquals(config.get("digits").intValue(), 42);
assertEquals(config.get("issuer").textValue(), "current-zone");
assertEquals(config.get("duration").intValue(), 13);
assertEquals(config.get("providerDescription").textValue(), "config description");
}

@Test
public void testDeserialize() {
String json = "{\n" +
" \"type\" : \"google-authenticator\",\n" +
" \"config\" : {\n" +
" \"providerDescription\" : \"ddd\",\n" +
" \"issuer\": \"issuer\",\n" +
" \"algorithm\": \"SHA256\",\n" +
" \"digits\": 8, \n" +
" \"duration\": 32 \n" +
" },\n" +
" \"name\" : \"UAA Provider\", \n" +
" \"active\" : true\n" +
"}";

MfaProvider<GoogleMfaProviderConfig> provider = JsonUtils.readValue(json, MfaProvider.class);

assertEquals(MfaProvider.MfaProviderType.GOOGLE_AUTHENTICATOR, provider.getType());
assertEquals("UAA Provider", provider.getName());
assertEquals(true, provider.isActive());
GoogleMfaProviderConfig config = provider.getConfig();
assertEquals(GoogleMfaProviderConfig.Algorithm.SHA256, config.getAlgorithm());
assertEquals(8, config.getDigits());
assertEquals(32, config.getDuration());
assertEquals("issuer", config.getIssuer());
assertEquals("ddd", config.getProviderDescription());

}

@Test @Test
public void validateProviderNullConfig() throws ValidationException { public void validateProviderNullConfig() throws ValidationException {
expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
Expand Down Expand Up @@ -68,10 +119,19 @@ public void validateProviderNullType() throws ValidationException {
provider.validate(); provider.validate();
} }


@Test
public void validateProviderEmptyZone() throws ValidationException {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Provider must belong to a zone");
MfaProvider provider = createValidGoogleMfaProvider()
.setIdentityZoneId("");
provider.validate();
}

@Test @Test
public void validateProviderActiveSetDefaultToTrue() { public void validateProviderActiveSetDefaultToTrue() {
MfaProvider provider = createValidGoogleMfaProvider(); MfaProvider provider = createValidGoogleMfaProvider();
assertTrue(provider.getActive()); assertTrue(provider.isActive());
} }


private MfaProvider createValidGoogleMfaProvider() { private MfaProvider createValidGoogleMfaProvider() {
Expand Down

0 comments on commit bbf6a19

Please sign in to comment.