package org.apereo.cas.services;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.OneToMany;
import javax.persistence.PostLoad;
import javax.persistence.Table;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Base class for mutable, persistable registered services.
*
* @author Marvin S. Addison
* @author Scott Battaglia
* @author Misagh Moayyed
* @since 3.0.0
*/
@Entity
@Inheritance
@DiscriminatorColumn(name = "expression_type", length = 15, discriminatorType = DiscriminatorType.STRING,
columnDefinition = "VARCHAR(15) DEFAULT 'ant'")
@Table(name = "RegexRegisteredService")
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
public abstract class AbstractRegisteredService implements RegisteredService {
private static final long serialVersionUID = 7645279151115635245L;
/**
* The unique identifier for this service.
*/
@Column(length = 255, updatable = true, insertable = true, nullable = false)
protected String serviceId;
@Column(length = 255, updatable = true, insertable = true, nullable = false)
private String name;
@Column(length = 255, updatable = true, insertable = true, nullable = true)
private String theme;
@Column(length = 255, updatable = true, insertable = true, nullable = true)
private String informationUrl;
@Column(length = 255, updatable = true, insertable = true, nullable = true)
private String privacyUrl;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id = RegisteredService.INITIAL_IDENTIFIER_VALUE;
@Column(length = 255, updatable = true, insertable = true, nullable = true)
private String description;
@Lob
@Column(name = "proxy_policy", nullable = true, length = Integer.MAX_VALUE)
private RegisteredServiceProxyPolicy proxyPolicy = new RefuseRegisteredServiceProxyPolicy();
@Column(name = "evaluation_order", nullable = false)
private int evaluationOrder;
@Lob
@Column(name = "username_attr", nullable = true, length = Integer.MAX_VALUE)
private RegisteredServiceUsernameAttributeProvider usernameAttributeProvider = new DefaultRegisteredServiceUsernameProvider();
@Column(name = "logout_type", nullable = true)
private LogoutType logoutType = LogoutType.BACK_CHANNEL;
@Lob
@Column(name = "required_handlers", length = Integer.MAX_VALUE)
private HashSet<String> requiredHandlers = new HashSet<>();
@Lob
@Column(name = "attribute_release", nullable = true, length = Integer.MAX_VALUE)
private RegisteredServiceAttributeReleasePolicy attributeReleasePolicy = new ReturnAllowedAttributeReleasePolicy();
@Lob
@Column(name = "mfa_policy", nullable = true, length = Integer.MAX_VALUE)
private RegisteredServiceMultifactorPolicy multifactorPolicy = new DefaultRegisteredServiceMultifactorPolicy();
@Column(name = "logo")
private URL logo;
@Column(name = "logout_url")
private URL logoutUrl;
@Lob
@Column(name = "access_strategy", nullable = true, length = Integer.MAX_VALUE)
private RegisteredServiceAccessStrategy accessStrategy = new DefaultRegisteredServiceAccessStrategy();
@Lob
@Column(name = "public_key", nullable = true, length = Integer.MAX_VALUE)
private RegisteredServicePublicKey publicKey;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name = "RegisteredServiceImpl_Props")
private Map<String, DefaultRegisteredServiceProperty> properties = new HashMap<>();
@Override
public long getId() {
return this.id;
}
@Override
public String getInformationUrl() {
return this.informationUrl;
}
@Override
public String getPrivacyUrl() {
return this.privacyUrl;
}
@Override
public String getDescription() {
return this.description;
}
@Override
public String getServiceId() {
return this.serviceId;
}
@Override
public String getName() {
return this.name;
}
@Override
public String getTheme() {
return this.theme;
}
@Override
public RegisteredServiceProxyPolicy getProxyPolicy() {
return this.proxyPolicy;
}
@Override
public RegisteredServiceAccessStrategy getAccessStrategy() {
return this.accessStrategy;
}
@Override
public URL getLogoutUrl() {
return this.logoutUrl;
}
/**
* Initializes the registered service with default values
* for fields that are unspecified. Only triggered by JPA.
*
* @since 4.1
*/
@PostLoad
public void postLoad() {
if (this.proxyPolicy == null) {
this.proxyPolicy = new RefuseRegisteredServiceProxyPolicy();
}
if (this.usernameAttributeProvider == null) {
this.usernameAttributeProvider = new DefaultRegisteredServiceUsernameProvider();
}
if (this.logoutType == null) {
this.logoutType = LogoutType.BACK_CHANNEL;
}
if (this.requiredHandlers == null) {
this.requiredHandlers = new HashSet<>();
}
if (this.accessStrategy == null) {
this.accessStrategy = new DefaultRegisteredServiceAccessStrategy();
}
if (this.multifactorPolicy == null) {
this.multifactorPolicy = new DefaultRegisteredServiceMultifactorPolicy();
}
if (this.properties == null) {
this.properties = new HashMap<>();
}
if (this.attributeReleasePolicy == null) {
this.attributeReleasePolicy = new ReturnAllowedAttributeReleasePolicy();
}
}
@Override
public boolean equals(final Object o) {
if (o == null) {
return false;
}
if (this == o) {
return true;
}
if (!(o instanceof AbstractRegisteredService)) {
return false;
}
final AbstractRegisteredService that = (AbstractRegisteredService) o;
final EqualsBuilder builder = new EqualsBuilder();
return builder
.append(this.proxyPolicy, that.proxyPolicy)
.append(this.evaluationOrder, that.evaluationOrder)
.append(this.description, that.description)
.append(this.name, that.name)
.append(this.serviceId, that.serviceId)
.append(this.theme, that.theme)
.append(this.usernameAttributeProvider, that.usernameAttributeProvider)
.append(this.logoutType, that.logoutType)
.append(this.attributeReleasePolicy, that.attributeReleasePolicy)
.append(this.accessStrategy, that.accessStrategy)
.append(this.logo, that.logo)
.append(this.publicKey, that.publicKey)
.append(this.logoutUrl, that.logoutUrl)
.append(this.requiredHandlers, that.requiredHandlers)
.append(this.proxyPolicy, that.proxyPolicy)
.append(this.properties, that.properties)
.append(this.multifactorPolicy, that.multifactorPolicy)
.append(this.informationUrl, that.informationUrl)
.append(this.privacyUrl, that.privacyUrl)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(7, 31)
.append(this.description)
.append(this.serviceId)
.append(this.name)
.append(this.theme)
.append(this.evaluationOrder)
.append(this.usernameAttributeProvider)
.append(this.accessStrategy)
.append(this.logoutType)
.append(this.attributeReleasePolicy)
.append(this.accessStrategy)
.append(this.logo)
.append(this.publicKey)
.append(this.logoutUrl)
.append(this.requiredHandlers)
.append(this.proxyPolicy)
.append(this.properties)
.append(this.multifactorPolicy)
.append(this.informationUrl)
.append(this.privacyUrl)
.toHashCode();
}
public void setProxyPolicy(final RegisteredServiceProxyPolicy policy) {
this.proxyPolicy = policy;
}
public void setDescription(final String description) {
this.description = description;
}
/**
* Sets the service identifier. Extensions are to define the format.
*
* @param id the new service id
*/
public abstract void setServiceId(String id);
public void setId(final long id) {
this.id = id;
}
public void setName(final String name) {
this.name = name;
}
public void setTheme(final String theme) {
this.theme = theme;
}
@Override
public void setEvaluationOrder(final int evaluationOrder) {
this.evaluationOrder = evaluationOrder;
}
@Override
public int getEvaluationOrder() {
return this.evaluationOrder;
}
@Override
public RegisteredServiceUsernameAttributeProvider getUsernameAttributeProvider() {
return this.usernameAttributeProvider;
}
public void setAccessStrategy(final RegisteredServiceAccessStrategy accessStrategy) {
this.accessStrategy = accessStrategy;
}
public void setLogoutUrl(final URL logoutUrl) {
this.logoutUrl = logoutUrl;
}
public void setInformationUrl(final String informationUrl) {
this.informationUrl = informationUrl;
}
public void setPrivacyUrl(final String privacyUrl) {
this.privacyUrl = privacyUrl;
}
/**
* Sets the user attribute provider instance
* when providing usernames to this registered service.
*
* @param usernameProvider the new username attribute
*/
public void setUsernameAttributeProvider(final RegisteredServiceUsernameAttributeProvider usernameProvider) {
this.usernameAttributeProvider = usernameProvider;
}
@JsonIgnore
@Override
public LogoutType getLogoutType() {
return this.logoutType;
}
/**
* Set the logout type of the service.
*
* @param logoutType the logout type of the service.
*/
public void setLogoutType(final LogoutType logoutType) {
this.logoutType = logoutType;
}
@Override
public AbstractRegisteredService clone() {
final AbstractRegisteredService clone = newInstance();
clone.copyFrom(this);
return clone;
}
/**
* Copies the properties of the source service into this instance.
*
* @param source Source service from which to copy properties.
*/
public void copyFrom(final RegisteredService source) {
setId(source.getId());
setProxyPolicy(source.getProxyPolicy());
setDescription(source.getDescription());
setName(source.getName());
setServiceId(source.getServiceId());
setTheme(source.getTheme());
setEvaluationOrder(source.getEvaluationOrder());
setUsernameAttributeProvider(source.getUsernameAttributeProvider());
setLogoutType(source.getLogoutType());
setAttributeReleasePolicy(source.getAttributeReleasePolicy());
setAccessStrategy(source.getAccessStrategy());
setLogo(source.getLogo());
setLogoutUrl(source.getLogoutUrl());
setPublicKey(source.getPublicKey());
setRequiredHandlers(source.getRequiredHandlers());
setProperties(source.getProperties());
setMultifactorPolicy(source.getMultifactorPolicy());
setInformationUrl(source.getInformationUrl());
setPrivacyUrl(source.getPrivacyUrl());
}
/**
* {@inheritDoc}
* Compares this instance with the {@code other} registered service based on
* evaluation order, name. The name comparison is case insensitive.
*
* @see #getEvaluationOrder()
*/
@Override
public int compareTo(final RegisteredService other) {
return new CompareToBuilder()
.append(getEvaluationOrder(), other.getEvaluationOrder())
.append(getName().toLowerCase(), other.getName().toLowerCase())
.append(getServiceId(), other.getServiceId())
.append(getId(), other.getId())
.toComparison();
}
@Override
public String toString() {
final ToStringBuilder toStringBuilder = new ToStringBuilder(null, ToStringStyle.SHORT_PREFIX_STYLE);
toStringBuilder.append("id", this.id);
toStringBuilder.append("name", this.name);
toStringBuilder.append("description", this.description);
toStringBuilder.append("serviceId", this.serviceId);
toStringBuilder.append("usernameAttributeProvider", this.usernameAttributeProvider);
toStringBuilder.append("theme", this.theme);
toStringBuilder.append("evaluationOrder", this.evaluationOrder);
toStringBuilder.append("logoutType", this.logoutType);
toStringBuilder.append("attributeReleasePolicy", this.attributeReleasePolicy);
toStringBuilder.append("accessStrategy", this.accessStrategy);
toStringBuilder.append("publicKey", this.publicKey);
toStringBuilder.append("proxyPolicy", this.proxyPolicy);
toStringBuilder.append("logo", this.logo);
toStringBuilder.append("logoutUrl", this.logoutUrl);
toStringBuilder.append("requiredHandlers", this.requiredHandlers);
toStringBuilder.append("properties", this.properties);
toStringBuilder.append("multifactorPolicy", this.multifactorPolicy);
toStringBuilder.append("informationUrl", this.informationUrl);
toStringBuilder.append("privacyUrl", this.privacyUrl);
return toStringBuilder.toString();
}
/**
* Create a new service instance.
*
* @return the registered service
*/
protected abstract AbstractRegisteredService newInstance();
@Override
public Set<String> getRequiredHandlers() {
if (this.requiredHandlers == null) {
this.requiredHandlers = new HashSet<>();
}
return this.requiredHandlers;
}
/**
* Sets the required handlers for this service.
*
* @param handlers the new required handlers
*/
public void setRequiredHandlers(final Set<String> handlers) {
getRequiredHandlers().clear();
if (handlers == null) {
return;
}
getRequiredHandlers().addAll(handlers);
}
/**
* Sets the attribute filtering policy.
*
* @param policy the new attribute filtering policy
*/
public void setAttributeReleasePolicy(final RegisteredServiceAttributeReleasePolicy policy) {
this.attributeReleasePolicy = policy;
}
@Override
public RegisteredServiceAttributeReleasePolicy getAttributeReleasePolicy() {
return this.attributeReleasePolicy;
}
@Override
public URL getLogo() {
return this.logo;
}
public void setLogo(final URL logo) {
this.logo = logo;
}
@Override
public RegisteredServicePublicKey getPublicKey() {
return this.publicKey;
}
public void setPublicKey(final RegisteredServicePublicKey publicKey) {
this.publicKey = publicKey;
}
@Override
public Map<String, RegisteredServiceProperty> getProperties() {
return (Map) this.properties;
}
public void setProperties(final Map<String, RegisteredServiceProperty> properties) {
this.properties = (Map) properties;
}
public RegisteredServiceMultifactorPolicy getMultifactorPolicy() {
return this.multifactorPolicy;
}
public void setMultifactorPolicy(final RegisteredServiceMultifactorPolicy multifactorPolicy) {
this.multifactorPolicy = multifactorPolicy;
}
}