org.plos.namedentity.api.entity.Auth.java Source code

Java tutorial

Introduction

Here is the source code for org.plos.namedentity.api.entity.Auth.java

Source

/*
 * Copyright (c) 2017 Public Library of Science
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */
package org.plos.namedentity.api.entity;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.plos.namedentity.api.NedException;
import org.plos.namedentity.service.PasswordDigestService;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.UUID;
import java.util.regex.Pattern;

import static org.plos.namedentity.api.NedException.ErrorType.CasIdError;
import static org.plos.namedentity.api.NedException.ErrorType.DigestPasswordError;
import static org.plos.namedentity.api.NedException.ErrorType.InvalidCasId;
import static org.plos.namedentity.api.NedException.ErrorType.PasswordError;
import static org.plos.namedentity.api.NedException.ErrorType.PasswordFormatError;
import static org.plos.namedentity.api.NedException.ErrorType.TamperedPasswordError;

import static org.plos.namedentity.service.PasswordDigestService.isValidDigestFormat;

@XmlRootElement
public class Auth extends Entity {

    public static final int PASSWORD_MIN_LENGTH = 8;

    private static final int CASID_MIN_LENGTH = 28;
    private static final int CASID_MAX_LENGTH = 36;

    private static final Pattern casRegex = Pattern.compile("^[A-Za-z0-9-]+$");
    private static final Pattern passwordRegexp = Pattern.compile("(\\d+\\D+)|(\\D+\\d+)");

    private String email;
    private Integer emailid;
    private String authid;

    // plain text password is a transient attribute used to generate the secure
    // password and in marshalling from json to pojo entity (not stored in db)
    private String plainTextPassword;

    // digested password (salt + hashed password) stored in db
    private String password;

    private Boolean passwordreset;
    private String verificationtoken;
    private Boolean verified;
    private Boolean isactive;

    public Auth() {
        this.authid = UUID.randomUUID().toString(); // cas id
    }

    private static String EXCLUDED_FIELDS[] = { "authid", "emailid", "isactive", "password", "plainTextPassword" };

    @Override
    public boolean equals(Object o) {
        return EqualsBuilder.reflectionEquals(this, o, concat(Entity.EXCLUDED_FIELDS, Auth.EXCLUDED_FIELDS));
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this, concat(Entity.EXCLUDED_FIELDS, Auth.EXCLUDED_FIELDS));
    }

    @Override
    public void validate() {
        validateAuthid(this.authid);
        validatePlainTextPassword(this.plainTextPassword);
        validatePasswordDigest(this.password);
    }

    public java.lang.Integer getEmailid() {
        return this.emailid;
    }

    public void setEmailid(java.lang.Integer emailid) {
        this.emailid = emailid;
    }

    public String getEmail() {
        return this.email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public java.lang.String getAuthid() {
        return this.authid;
    }

    public void setAuthid(java.lang.String authid) {
        this.authid = authid;
    }

    @XmlElement(name = "password")
    public String getPlainTextPassword() {
        return this.plainTextPassword;
    }

    @XmlElement(name = "password")
    public void setPlainTextPassword(String plainTextPassword) {
        this.plainTextPassword = plainTextPassword;
        if (plainTextPassword != null) {
            setPassword(new PasswordDigestService().generateDigest(plainTextPassword));
        }
    }

    public String getPassword() {
        return this.password;
    }

    // setter called from 1. plaintext setter, 2. jooq populating pojo from db,
    // and 3. etl migrating ambra password.
    @XmlElement(name = "password_digest")
    public void setPassword(String hashedPassword) {
        this.password = hashedPassword;
    }

    public Boolean getPasswordreset() {
        return this.passwordreset;
    }

    public void setPasswordreset(Boolean passwordreset) {
        this.passwordreset = passwordreset;
    }

    public java.lang.String getVerificationtoken() {
        return this.verificationtoken;
    }

    public void setVerificationtoken(java.lang.String verificationtoken) {
        this.verificationtoken = verificationtoken;
    }

    public Boolean getVerified() {
        return this.verified;
    }

    public void setVerified(Boolean verified) {
        this.verified = verified;
    }

    public Boolean getIsactive() {
        return this.isactive;
    }

    public void setIsactive(Boolean isactive) {
        this.isactive = isactive;
    }

    private String[] concat(String[] a, String[] b) {
        String[] c = new String[a.length + b.length];
        System.arraycopy(a, 0, c, 0, a.length);
        System.arraycopy(b, 0, c, a.length, b.length);
        return c;
    }

    private void validateAuthid(String casid) {
        if (casid == null) {
            throw new NedException(CasIdError, "undefined cas id. this is a required field.");
        }

        if (casid.length() < CASID_MIN_LENGTH)
            throw new NedException(InvalidCasId,
                    "CAS ID can not be shorter then " + CASID_MIN_LENGTH + " characters");

        if (casid.length() > CASID_MAX_LENGTH)
            throw new NedException(InvalidCasId,
                    "CAS ID can not be longer then " + CASID_MAX_LENGTH + " characters");

        if (!casRegex.matcher(casid).matches())
            throw new NedException(InvalidCasId, "CAS ID contains invalid characters");
    }

    private void validatePlainTextPassword(String password) {
        // only validate if not null
        if (password != null) {
            if (password.length() < PASSWORD_MIN_LENGTH)
                throw new NedException(PasswordFormatError,
                        "password must be at least " + PASSWORD_MIN_LENGTH + " characters");
            if (!passwordRegexp.matcher(password).find())
                throw new NedException(PasswordFormatError,
                        "password must contain at least one number and one non-number");
        }
    }

    private void validatePasswordDigest(String password) {
        if (password == null) {
            throw new NedException(PasswordError, "undefined password. this is a required field.");
        }
        if (!isValidDigestFormat(password)) {
            throw new NedException(DigestPasswordError,
                    String.format("invalid encoded password (length:%d)", password.length()));
        }
        if (plainTextPassword != null) {
            boolean verifyResult = new PasswordDigestService().verifyPassword(plainTextPassword, password);
            if (!verifyResult) {
                throw new NedException(TamperedPasswordError, "secure password doesn't match input password");
            }
        }
    }
}