All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.krotscheck.kangaroo.authz.common.database.entity.Client Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
/*
 * Copyright (c) 2016 Michael Krotscheck
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy
 * of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package net.krotscheck.kangaroo.authz.common.database.entity;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.common.base.Strings;
import io.swagger.annotations.ApiModelProperty;
import net.krotscheck.kangaroo.common.hibernate.id.AbstractEntityReferenceDeserializer;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.ContainedIn;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.search.annotations.Store;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapKeyColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * This represents a registered client, as well as it's connection metadata,
 * for
 * a specific application. Multiple different clients may exist per
 * application.
 *
 * @author Michael Krotscheck
 */
@Entity
@Table(name = "clients")
@Indexed(index = "clients")
@Analyzer(definition = "entity_analyzer")
public final class Client extends AbstractAuthzEntity {

    /**
     * The Application to whom this client belongs.
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "application", nullable = false, updatable = false)
    @JsonIdentityReference(alwaysAsId = true)
    @JsonIdentityInfo(
            generator = ObjectIdGenerators.PropertyGenerator.class,
            property = "id")
    @JsonDeserialize(using = Application.Deserializer.class)
    @IndexedEmbedded(includePaths = {"id", "owner.id"})
    @ApiModelProperty(
            required = true,
            dataType = "string",
            example = "3f631a2d6a04f5cc55f9e192f45649b7"
    )
    private Application application;

    /**
     * List of the application's authenticators.
     */
    @OneToMany(
            fetch = FetchType.LAZY,
            mappedBy = "client",
            cascade = {CascadeType.REMOVE},
            orphanRemoval = true
    )
    @JsonIgnore
    @OnDelete(action = OnDeleteAction.CASCADE)
    private List authenticators = new ArrayList<>();

    /**
     * OAuth tokens issued to this client.
     */
    @OneToMany(
            fetch = FetchType.LAZY,
            mappedBy = "client",
            cascade = {CascadeType.REMOVE, CascadeType.MERGE},
            orphanRemoval = true
    )
    @JsonIgnore
    @OnDelete(action = OnDeleteAction.CASCADE)
    @ContainedIn
    private List tokens = new ArrayList<>();

    /**
     * Human recognizable name for this client.
     */
    @Basic(optional = false)
    @Column(name = "name", nullable = false)
    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
    @Size(min = 3, max = 255, message = "Client name must be between 3 "
            + "and 255 characters.")
    @ApiModelProperty(required = true)
    private String name;

    /**
     * Human recognizable name for this client.
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "type", nullable = false)
    @NotNull
    private ClientType type;

    /**
     * A client secret, indicating a password which must be provided to the
     * client.
     */
    @Basic
    @Column(name = "clientSecret", updatable = true, nullable = true)
    private String clientSecret;

    /**
     * A collection of referral URL's, used for CORS matching.
     */
    @OneToMany(
            fetch = FetchType.LAZY,
            mappedBy = "client",
            cascade = {CascadeType.ALL},
            orphanRemoval = true
    )
    @JsonIgnore
    @OnDelete(action = OnDeleteAction.CASCADE)
    @IndexedEmbedded(includePaths = {"id", "uri"})
    private List referrers = new ArrayList<>();

    /**
     * A list of redirect URL's, used for redirection-based flows.
     */
    @OneToMany(
            fetch = FetchType.LAZY,
            mappedBy = "client",
            cascade = {CascadeType.REMOVE},
            orphanRemoval = true
    )
    @JsonIgnore
    @OnDelete(action = OnDeleteAction.CASCADE)
    @IndexedEmbedded(includePaths = {"id", "uri"})
    private List redirects = new ArrayList<>();

    /**
     * The configuration settings for this application.
     */
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "client_configs",
                     joinColumns = @JoinColumn(name = "client"))
    @MapKeyColumn(name = "configKey")
    @Column(name = "configValue")
    private Map configuration = new TreeMap<>();

    /**
     * Get the application this client belongs to.
     *
     * @return The application.
     */
    public Application getApplication() {
        return application;
    }

    /**
     * Set the application which this client belongs to.
     *
     * @param application The new application.
     */
    public void setApplication(final Application application) {
        this.application = application;
    }

    /**
     * Get the name for this client.
     *
     * @return The client's human-readable name.
     */
    public String getName() {
        return name;
    }

    /**
     * Set the client's name.
     *
     * @param name The name to use, should be human-readable.
     */
    public void setName(final String name) {
        this.name = name;
    }

    /**
     * Retrieve the client secret.
     *
     * @return The client secret.
     */
    public String getClientSecret() {
        return clientSecret;
    }

    /**
     * Set the client secret.
     *
     * @param clientSecret A new client secret.
     */
    public void setClientSecret(final String clientSecret) {
        this.clientSecret = clientSecret;
    }

    /**
     * Get the list of valid referrers.
     *
     * @return This client's list of valid referrers.
     */
    public List getReferrers() {
        return referrers;
    }

    /**
     * Update the set of valid referrers.
     *
     * @param referrers A new set of referrers.
     */
    public void setReferrers(final List referrers) {
        this.referrers = new ArrayList<>(referrers);
    }

    /**
     * Get the valid redirect URI's.
     *
     * @return The valid redirect url's.
     */
    public List getRedirects() {
        return redirects;
    }

    /**
     * Set the list of redirects.
     *
     * @param redirects The redirects.
     */
    public void setRedirects(final List redirects) {
        this.redirects = new ArrayList<>(redirects);
    }

    /**
     * The list of authenticators active in this client.
     *
     * @return The list of authenticators.
     */
    public List getAuthenticators() {
        return authenticators;
    }

    /**
     * Set the authenticators.
     *
     * @param authenticators New list of authenticators.
     */
    public void setAuthenticators(final List authenticators) {
        this.authenticators = new ArrayList<>(authenticators);
    }

    /**
     * Get all the tokens issued under this client.
     *
     * @return A list of all tokens (lazy loaded)
     */
    public List getTokens() {
        return tokens;
    }

    /**
     * Set the list of tokens for this client.
     *
     * @param tokens A new list of tokens.
     */
    public void setTokens(final List tokens) {
        this.tokens = new ArrayList<>(tokens);
    }

    /**
     * Get the client type.
     *
     * @return The client type.
     */
    public ClientType getType() {
        return type;
    }

    /**
     * Set the client type.
     *
     * @param type The client type!
     */
    public void setType(final ClientType type) {
        this.type = type;
    }

    /**
     * Retrieve configuration for this client.
     *
     * @return A set of configuration elements, such as token expiry.
     */
    public Map getConfiguration() {
        return configuration;
    }

    /**
     * Set the configuration for this client.
     *
     * @param configuration The new configuration.
     */
    public void setConfiguration(final Map configuration) {
        this.configuration = new HashMap<>(configuration);
    }

    /**
     * Extract the authorization code expiration time (in seconds) for this
     * client. This value is derived from the default configuration values, or
     * from a default, if such exists.
     *
     * @return The expiration horizon of an access token, in seconds.
     */
    @JsonIgnore
    public Integer getAuthorizationCodeExpiresIn() {
        try {
            Map config = getConfiguration();
            String value =
                    config.get(ClientConfig.AUTHORIZATION_CODE_EXPIRES_NAME);
            return Integer.parseInt(value);
        } catch (Exception e) {
            return ClientConfig.AUTHORIZATION_CODE_EXPIRES_DEFAULT;
        }
    }

    /**
     * Extract the access token expiration time (in seconds) for this client.
     * This value is derived from the default configuration values, or from a
     * default, if such exists.
     *
     * @return The expiration horizon of an access token, in seconds.
     */
    @JsonIgnore
    public Integer getAccessTokenExpireIn() {
        try {
            Map config = getConfiguration();
            String value = config.get(ClientConfig.ACCESS_TOKEN_EXPIRES_NAME);
            return Integer.parseInt(value);
        } catch (Exception e) {
            return ClientConfig.ACCESS_TOKEN_EXPIRES_DEFAULT;
        }
    }

    /**
     * Extract the refresh token expiration time (in seconds) for this client.
     * This value is derived from the default configuration values, or from a
     * default, if such exists.
     *
     * @return The expiration horizon of an access token, in seconds.
     */
    @JsonIgnore
    public Integer getRefreshTokenExpireIn() {
        try {
            Map config = getConfiguration();
            String value = config.get(ClientConfig.REFRESH_TOKEN_EXPIRES_NAME);
            return Integer.parseInt(value);
        } catch (Exception e) {
            return ClientConfig.REFRESH_TOKEN_EXPIRES_DEFAULT;
        }
    }

    /**
     * The owner of this entity.
     *
     * @return This entity's owner, if it exists.
     */
    @Override
    @Transient
    @JsonIgnore
    public User getOwner() {
        if (application != null) {
            return application.getOwner();
        }
        return null;
    }

    /**
     * Whether this client is private.
     *
     * @return true, if this is a private client, otherwise false.
     */
    @Transient
    @JsonIgnore
    public Boolean isPrivate() {
        return !Strings.isNullOrEmpty(clientSecret);
    }

    /**
     * Whether this client is public.
     *
     * @return true, if this is a public client, otherwise false.
     */
    @Transient
    @JsonIgnore
    public Boolean isPublic() {
        return !isPrivate();
    }

    /**
     * Deserialize a reference to an User.
     *
     * @author Michael Krotschecks
     */
    public static final class Deserializer
            extends AbstractEntityReferenceDeserializer {

        /**
         * Constructor.
         */
        public Deserializer() {
            super(Client.class);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy