LocalAccount.java
- /*
- * The coLAB project
- * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO
- *
- * Licensed under the MIT License
- */
- package ch.colabproject.colab.api.model.user;
- import ch.colabproject.colab.api.Helper;
- import ch.colabproject.colab.api.exceptions.ColabMergeException;
- import ch.colabproject.colab.api.model.ColabEntity;
- import javax.json.bind.annotation.JsonbTransient;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.EnumType;
- import javax.persistence.Enumerated;
- import javax.persistence.Index;
- import javax.persistence.NamedQuery;
- import javax.persistence.Table;
- import javax.validation.constraints.Email;
- import javax.validation.constraints.NotNull;
- import javax.validation.constraints.Size;
- /**
- * Password based authentication.
- *
- * @author maxence
- */
- @Entity
- @NamedQuery(name = "LocalAccount.findByEmail",
- query = "SELECT a from LocalAccount a where a.email = :email")
- @Table(
- // make sure to have JOINED inheritance, otherwise indexes and constraints will be ignored!
- indexes = {
- @Index(columnList = "email", unique = true)
- })
- public class LocalAccount extends Account {
- private static final long serialVersionUID = 1L;
- // ---------------------------------------------------------------------------------------------
- // fields
- // ---------------------------------------------------------------------------------------------
- /**
- * username-like email address
- */
- @Size(max = 255)
- @Email
- @NotNull
- private String email;
- /**
- * salt+password hash. Hashed with currentDbHashMethod and dbSalt.
- */
- @JsonbTransient
- @NotNull
- private byte[] hashedPassword;
- /**
- * Has the email address been verified with a VerificationToken ?
- */
- @NotNull
- private Boolean verified;
- /**
- * Salt to used before hashing the password
- */
- @JsonbTransient
- @NotNull
- private byte[] dbSalt;
- /**
- * Hash method to use to hashedPassword the salt+password
- */
- @Column(length = 100)
- @Enumerated(value = EnumType.STRING)
- @JsonbTransient
- @NotNull
- private HashMethod currentDbHashMethod;
- /**
- * New hash method to use to hash the salt+password. If not null, rotate hash method on next
- * successful authentication
- */
- @Column(length = 100)
- @Enumerated(value = EnumType.STRING)
- @JsonbTransient
- private HashMethod nextDbHashMethod;
- /**
- * Salt the client shall use to before hashing its password. Salt is hex-encoded byte array
- */
- @Size(max = 255)
- @NotNull
- @JsonbTransient
- private String clientSalt;
- /**
- * New salt the client shall use to prefix its password before hashing it.
- * <p>
- * In case this is not null, client shall send two hashes. First one is the plain_password
- * prefixed with clientSalt and hashed with currentClientHashMethod (to authenticate), second is
- * its password prefixed with this new salt and hashed with nextClientHashMethod if set, current
- * otherwise. successful authentication (to rotate salt and/or method)
- */
- @Size(max = 255)
- @JsonbTransient
- private String newClientSalt;
- /**
- * Hash method the client shall use to hashedPassword the clientSalt+plain_password
- */
- @Column(length = 100)
- @Enumerated(value = EnumType.STRING)
- @NotNull
- @JsonbTransient
- private HashMethod currentClientHashMethod;
- /**
- * New hash method the client shall use to hash its clientSalt+plain_password.
- * <p>
- * In case this is not null, client shall send two hashes. First one is its plain_password
- * prefixed clientSalt and hashed with currentClientHashMethod (to authenticate), second is its
- * password prefixed with the new_salt (if set)or the current salt and hashed with this method
- */
- @Column(length = 100)
- @Enumerated(value = EnumType.STRING)
- @JsonbTransient
- private HashMethod nextClientHashMethod;
- // ---------------------------------------------------------------------------------------------
- // getters and setters
- // ---------------------------------------------------------------------------------------------
- /**
- * @return email associated with this account
- */
- public String getEmail() {
- return email;
- }
- /**
- * update email. If the email is not the same, this account will not be verified any longer
- *
- * @param email new email to use.
- */
- public void setEmail(String email) {
- if (Helper.isEmailAddress(email)) { // FIXME sandra see with Maxence if it is useful to do
- // it here
- if (!email.equals(this.email)) {
- this.verified = false;
- }
- this.email = email;
- }
- }
- /**
- * get the stored hashedPassword to challenge authentication against
- *
- * @return hashedPassword hashedPassword to challenge authentication against
- */
- public byte[] getHashedPassword() {
- return hashedPassword;
- }
- /**
- * Update hashedPassword
- *
- * @param hashedPassword new hashedPassword
- */
- public void setHashedPassword(byte[] hashedPassword) {
- this.hashedPassword = hashedPassword;
- }
- /**
- * has the email address been verified ?
- *
- * @return true if the account is verified
- */
- public Boolean isVerified() {
- return verified;
- }
- /**
- * Set if the account has been verified or not
- *
- * @param verified yes or no ?
- */
- public void setVerified(Boolean verified) {
- this.verified = verified;
- }
- /**
- * @return the salt to used server-side
- */
- public byte[] getDbSalt() {
- return dbSalt;
- }
- /**
- * Update the server-side hashedPassword
- *
- * @param dbSalt new server-side salt
- */
- public void setDbSalt(byte[] dbSalt) {
- this.dbSalt = dbSalt;
- }
- /**
- * @return the current hashedPassword method to used to hashedPassword provided password
- */
- public HashMethod getCurrentDbHashMethod() {
- return currentDbHashMethod;
- }
- /**
- * Set the method to use to hashedPassword provided password
- *
- * @param currentDbHashMethod hashedPassword method
- */
- public void setCurrentDbHashMethod(HashMethod currentDbHashMethod) {
- this.currentDbHashMethod = currentDbHashMethod;
- }
- /**
- * @return the next hashedPassword method to use. If not null, hashedPassword methods will be
- * rotated on next authentication
- */
- public HashMethod getNextDbHashMethod() {
- return nextDbHashMethod;
- }
- /**
- * change the next hashedPassword method to used
- *
- * @param nextDbHashMethod next hashedPassword method
- */
- public void setNextDbHashMethod(HashMethod nextDbHashMethod) {
- this.nextDbHashMethod = nextDbHashMethod;
- }
- /**
- * @return the salt the user shall use before client-side plain_password hashedPassword
- */
- public String getClientSalt() {
- return clientSalt;
- }
- /**
- * Update the salt the client shall use
- *
- * @param clientSalt client salt
- */
- public void setClientSalt(String clientSalt) {
- this.clientSalt = clientSalt;
- }
- /**
- * @return the salt to use to rotate authentication
- */
- public String getNewClientSalt() {
- return newClientSalt;
- }
- /**
- * set a next client-side salt
- *
- * @param newClientSalt new salt we want the client to use
- */
- public void setNewClientSalt(String newClientSalt) {
- this.newClientSalt = newClientSalt;
- }
- /**
- * @return the hashedPassword method the client shall use to hashedPassword its
- * salt+plain_password
- */
- public HashMethod getCurrentClientHashMethod() {
- return currentClientHashMethod;
- }
- /**
- * CHange hashedPassword method the client shall use
- *
- * @param currentClientHashMethod hashedPassword method the client shall use
- */
- public void setCurrentClientHashMethod(HashMethod currentClientHashMethod) {
- this.currentClientHashMethod = currentClientHashMethod;
- }
- /**
- * @return the next hashedPassword method the client shall use
- */
- public HashMethod getNextClientHashMethod() {
- return nextClientHashMethod;
- }
- /**
- * Update the next client-side hashedPassword method
- *
- * @param nextClientHashMethod new next client hashedPassword method
- */
- public void setNextClientHashMethod(HashMethod nextClientHashMethod) {
- this.nextClientHashMethod = nextClientHashMethod;
- }
- // ---------------------------------------------------------------------------------------------
- // concerning the whole class
- // ---------------------------------------------------------------------------------------------
- @Override
- public void mergeToUpdate(ColabEntity other) throws ColabMergeException {
- if (other instanceof LocalAccount) {
- LocalAccount o = (LocalAccount) other;
- this.setDeletionStatus(o.getDeletionStatus());
- this.setEmail(o.getEmail());
- // the others fields cannot be changed by a simple update
- } else {
- throw new ColabMergeException(this, other);
- }
- }
- @Override
- public String toString() {
- return "LocalAccount{" + "id=" + this.getId() + ", deletion=" + getDeletionStatus()
- + ", email=" + email + ", verified=" + verified + '}';
- }
- }