/******************************************************************************* * Cloud Foundry * Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved. * * This product is licensed to you under the Apache License, Version 2.0 (the "License"). * You may not use this product except in compliance with the License. * * This product includes a number of subcomponents with * separate copyright notices and license terms. Your use of these * subcomponents is subject to the terms and conditions of the * subcomponent's license, as noted in the LICENSE file. *******************************************************************************/ package org.cloudfoundry.identity.uaa.provider; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.cloudfoundry.identity.uaa.util.JsonUtils; import org.springframework.util.StringUtils; import javax.validation.constraints.NotNull; import java.io.IOException; import java.util.Date; 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.getNodeAsDate; import static org.cloudfoundry.identity.uaa.util.JsonUtils.getNodeAsInt; import static org.cloudfoundry.identity.uaa.util.JsonUtils.getNodeAsString; @JsonSerialize(using = IdentityProvider.IdentityProviderSerializer.class) @JsonDeserialize(using = IdentityProvider.IdentityProviderDeserializer.class) public class IdentityProvider<T extends AbstractIdentityProviderDefinition> { public static final String FIELD_ID = "id"; public static final String FIELD_ORIGIN_KEY = "originKey"; public static final String FIELD_NAME = "name"; public static final String FIELD_VERSION = "version"; public static final String FIELD_CREATED = "created"; public static final String FIELD_LAST_MODIFIED = "last_modified"; public static final String FIELD_ACTIVE = "active"; public static final String FIELD_IDENTITY_ZONE_ID = "identityZoneId"; public static final String FIELD_CONFIG = "config"; public static final String FIELD_TYPE = "type"; //see deserializer at the bottom private String id; @NotNull private String originKey; @NotNull private String name; @NotNull private String type; private T config; private int version = 0; private Date created = new Date(); @JsonProperty("last_modified") private Date lastModified = new Date(); private boolean active = true; private String identityZoneId; public Date getCreated() { return created; } public IdentityProvider setCreated(Date created) { this.created = created; return this; } public Date getLastModified() { return lastModified; } public IdentityProvider setLastModified(Date lastModified) { this.lastModified = lastModified; return this; } public IdentityProvider setVersion(int version) { this.version = version; return this; } public int getVersion() { return version; } public String getName() { return name; } public IdentityProvider setName(String name) { this.name = name; return this; } public String getId() { return id; } public IdentityProvider setId(String id) { this.id = id; return this; } public T getConfig() { return config; } public IdentityProvider setConfig(T config) { if (config == null) { this.type = UNKNOWN; } else { Class clazz = config.getClass(); if (SamlIdentityProviderDefinition.class.isAssignableFrom(clazz)) { this.type = SAML; if (StringUtils.hasText(getOriginKey())) { ((SamlIdentityProviderDefinition) config).setIdpEntityAlias(getOriginKey()); } if (StringUtils.hasText(getIdentityZoneId())) { ((SamlIdentityProviderDefinition) config).setZoneId(getIdentityZoneId()); } } else if (UaaIdentityProviderDefinition.class.isAssignableFrom(clazz)) { this.type = UAA; } else if (RawXOAuthIdentityProviderDefinition.class.isAssignableFrom(clazz)) { this.type = OAUTH20; } else if (OIDCIdentityProviderDefinition.class.isAssignableFrom(clazz)) { this.type = OIDC10; } else if (LdapIdentityProviderDefinition.class.isAssignableFrom(clazz)) { this.type = LDAP; } else if (KeystoneIdentityProviderDefinition.class.isAssignableFrom(clazz)) { this.type = KEYSTONE; } else if (AbstractIdentityProviderDefinition.class.isAssignableFrom(clazz)) { this.type = UNKNOWN; } else { throw new IllegalArgumentException("Unknown identity provider configuration type:" + clazz.getName()); } } this.config = config; return this; } public String getOriginKey() { return originKey; } public IdentityProvider setOriginKey(String originKey) { this.originKey = originKey; if (config != null && config instanceof SamlIdentityProviderDefinition) { ((SamlIdentityProviderDefinition) config).setIdpEntityAlias(originKey); } return this; } public String getType() { return type; } public IdentityProvider setType(String type) { this.type = type; return this; } public boolean isActive() { return active; } public IdentityProvider setActive(boolean active) { this.active = active; return this; } public String getIdentityZoneId() { return identityZoneId; } public IdentityProvider setIdentityZoneId(String identityZoneId) { this.identityZoneId = identityZoneId; if (config != null && config instanceof SamlIdentityProviderDefinition) { ((SamlIdentityProviderDefinition) config).setZoneId(identityZoneId); } return this; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((config == null) ? 0 : config.hashCode()); result = prime * result + ((created == null) ? 0 : created.hashCode()); result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((originKey == null) ? 0 : originKey.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); result = prime * result + version; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; IdentityProvider other = (IdentityProvider) obj; if (config == null) { if (other.config != null) return false; } else if (!config.equals(other.config)) return false; if (created == null) { if (other.created != null) return false; } else if (!created.equals(other.created)) return false; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (lastModified == null) { if (other.lastModified != null) return false; } else if (!lastModified.equals(other.lastModified)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (originKey == null) { if (other.originKey != null) return false; } else if (!originKey.equals(other.originKey)) return false; if (type == null) { if (other.type != null) return false; } else if (!type.equals(other.type)) return false; if (version != other.version) return false; return true; } @Override public String toString() { final StringBuffer sb = new StringBuffer("IdentityProvider{"); sb.append("id='").append(id).append('\''); sb.append(", originKey='").append(originKey).append('\''); sb.append(", name='").append(name).append('\''); sb.append(", type='").append(type).append('\''); sb.append(", active=").append(active); sb.append('}'); return sb.toString(); } private boolean serializeConfigRaw; @JsonIgnore public boolean isSerializeConfigRaw() { return serializeConfigRaw; } @JsonIgnore public void setSerializeConfigRaw(boolean serializeConfigRaw) { this.serializeConfigRaw = serializeConfigRaw; } public static class IdentityProviderSerializer extends JsonSerializer<IdentityProvider> { @Override public void serialize(IdentityProvider value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException { gen.writeStartObject(); gen.writeStringField(FIELD_TYPE, value.getType()); if (value.isSerializeConfigRaw()) { gen.writeObjectField(FIELD_CONFIG, value.getConfig()); } else { gen.writeStringField(FIELD_CONFIG, JsonUtils.writeValueAsString(value.getConfig())); } gen.writeStringField(FIELD_ID, value.getId()); gen.writeStringField(FIELD_ORIGIN_KEY, value.getOriginKey()); gen.writeStringField(FIELD_NAME, value.getName()); gen.writeNumberField(FIELD_VERSION, value.getVersion()); writeDateField(FIELD_CREATED, value.getCreated(), gen); writeDateField(FIELD_LAST_MODIFIED, value.getLastModified(), gen); gen.writeBooleanField(FIELD_ACTIVE, value.isActive()); gen.writeStringField(FIELD_IDENTITY_ZONE_ID, value.getIdentityZoneId()); gen.writeEndObject(); } public void writeDateField(String fieldName, Date value, JsonGenerator gen) throws IOException { if (value != null) { gen.writeNumberField(fieldName, value.getTime()); } else { gen.writeNullField(fieldName); } } } public static class IdentityProviderDeserializer extends JsonDeserializer<IdentityProvider> { @Override public IdentityProvider deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { IdentityProvider result = new IdentityProvider(); //determine the type of IdentityProvider JsonNode node = JsonUtils.readTree(jp); String type = getNodeAsString(node, FIELD_TYPE, UNKNOWN); //deserialize based on type String config; JsonNode configNode = node.get("config"); if (configNode == null) { config = null; } else if (configNode.isTextual()) { config = configNode.textValue(); } else { config = configNode.toString(); } AbstractIdentityProviderDefinition definition = null; if (StringUtils.hasText(config)) { switch (type) { case SAML: definition = JsonUtils.readValue(config, SamlIdentityProviderDefinition.class); break; case OAUTH20: definition = JsonUtils.readValue(config, RawXOAuthIdentityProviderDefinition.class); break; case OIDC10: definition = JsonUtils.readValue(config, OIDCIdentityProviderDefinition.class); break; case UAA: definition = JsonUtils.readValue(config, UaaIdentityProviderDefinition.class); break; case LDAP: definition = JsonUtils.readValue(config, LdapIdentityProviderDefinition.class); break; case KEYSTONE: definition = JsonUtils.readValue(config, KeystoneIdentityProviderDefinition.class); break; default: definition = JsonUtils.readValue(config, AbstractIdentityProviderDefinition.class); break; } } result.setConfig(definition); result.setType(type); result.setId(getNodeAsString(node, FIELD_ID, null)); result.setOriginKey(getNodeAsString(node, FIELD_ORIGIN_KEY, null)); result.setName(getNodeAsString(node, FIELD_NAME, null)); result.setVersion(getNodeAsInt(node, FIELD_VERSION, 0)); result.setCreated(getNodeAsDate(node, FIELD_CREATED)); result.setLastModified(getNodeAsDate(node, FIELD_LAST_MODIFIED)); result.setActive(getNodeAsBoolean(node, FIELD_ACTIVE, true)); result.setIdentityZoneId(getNodeAsString(node, FIELD_IDENTITY_ZONE_ID, null)); return result; } } }