branch develop updated (70121878 -> eb65c638)
This is an automated email from the git hooks/post-receive script. New change to branch develop in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git from 70121878 refs #192 : Restreindre un sondage sur les emails des votants new eb65c638 refs #173 : Validation des emails sans token en base The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit eb65c6382a3a215f8bee9b5f78b746273aad4d1b Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Wed Jun 13 14:12:35 2018 +0200 refs #173 : Validation des emails sans token en base Summary of changes: docs/config.md | 2 +- .../entity/PollenUserEmailAddressTopiaDao.java | 11 ----- .../pollen/persistence/entity/PollenUserImpl.java | 2 +- .../h2/V3_2_0_4__use_JWT_for_validate_email.sql | 19 ++++++++ .../V3_2_0_4__use_JWT_for_validate_email.sql | 19 ++++++++ pollen-persistence/src/main/xmi/pollen.properties | 2 +- pollen-persistence/src/main/xmi/pollen.zargo | Bin 31056 -> 30935 bytes pollen-services/src/main/config/PollenServices.ini | 2 +- .../services/config/PollenServicesConfig.java | 8 ++- .../pollen/services/service/CryptoService.java | 45 +++++++++++++++-- .../services/service/NotificationService.java | 12 ++--- .../pollen/services/service/PollenUserService.java | 38 +++++++-------- .../pollen/services/service/mail/EmailService.java | 13 +++-- .../services/service/security/SecurityService.java | 54 ++++++++++++++++++--- .../i18n/pollen-services_en_GB.properties | 2 +- .../i18n/pollen-services_fr_FR.properties | 2 +- 16 files changed, 169 insertions(+), 62 deletions(-) create mode 100644 pollen-persistence/src/main/resources/db/migration/h2/V3_2_0_4__use_JWT_for_validate_email.sql create mode 100644 pollen-persistence/src/main/resources/db/migration/postgresql/V3_2_0_4__use_JWT_for_validate_email.sql -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit eb65c6382a3a215f8bee9b5f78b746273aad4d1b Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Wed Jun 13 14:12:35 2018 +0200 refs #173 : Validation des emails sans token en base --- docs/config.md | 2 +- .../entity/PollenUserEmailAddressTopiaDao.java | 11 ----- .../pollen/persistence/entity/PollenUserImpl.java | 2 +- .../h2/V3_2_0_4__use_JWT_for_validate_email.sql | 19 ++++++++ .../V3_2_0_4__use_JWT_for_validate_email.sql | 19 ++++++++ pollen-persistence/src/main/xmi/pollen.properties | 2 +- pollen-persistence/src/main/xmi/pollen.zargo | Bin 31056 -> 30935 bytes pollen-services/src/main/config/PollenServices.ini | 2 +- .../services/config/PollenServicesConfig.java | 8 ++- .../pollen/services/service/CryptoService.java | 45 +++++++++++++++-- .../services/service/NotificationService.java | 12 ++--- .../pollen/services/service/PollenUserService.java | 38 +++++++-------- .../pollen/services/service/mail/EmailService.java | 13 +++-- .../services/service/security/SecurityService.java | 54 ++++++++++++++++++--- .../i18n/pollen-services_en_GB.properties | 2 +- .../i18n/pollen-services_fr_FR.properties | 2 +- 16 files changed, 169 insertions(+), 62 deletions(-) diff --git a/docs/config.md b/docs/config.md index 52b37094..460001b1 100644 --- a/docs/config.md +++ b/docs/config.md @@ -78,7 +78,7 @@ Si le mail reçu provient d’un retour d’une invitation à un sondage, il ser | Clés | Descriptions | Types | Valeurs par défaut | |---------------------------------------------------|-------------------------------------------------------------------------------------------------------|-----------------------------------------------|-----------------------| | pollen.data.directory | Répertoire de données de l’application | Alpha-numérique | | -| pollen.token.secret | Clés de chiffrement des jetons d'authentification | Alpha-numérique | !secret# | +| pollen.token.secret | Clés de chiffrement des jetons d'authentification (encodé en base 64)(16, 24 ou 32 bytes) | Alpha-numérique | IFYD6KLx/GrLZwSFBH5arXMIamWSA8qiVtFImIimDZs= | | pollen.token.issue | Le nom de l'émetteur des jetons d'authentification | Alpha-numérique | Pollen | | pollen.token.timeout | Durée de validité d'un jeton d'authentification (en secondes) | Numérique | 3600 | | pollen.default.pollType | Type de sondage par défaut lors de la création d'un nouveau sondage | FREE, RESTRICTED | FREE | diff --git a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserEmailAddressTopiaDao.java b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserEmailAddressTopiaDao.java index 968be61a..988b2db5 100644 --- a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserEmailAddressTopiaDao.java +++ b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserEmailAddressTopiaDao.java @@ -21,22 +21,11 @@ package org.chorem.pollen.persistence.entity; * #L% */ -import java.util.HashMap; -import java.util.Map; - public class PollenUserEmailAddressTopiaDao extends AbstractPollenUserEmailAddressTopiaDao<PollenUserEmailAddress> { public boolean emailExists(String email) { return forEmailAddressEquals(email).exists(); } - public PollenUserEmailAddress findEmailAddressByToken(String token) { - String hql = newFromClause() + - " WHERE " + PollenUserEmailAddress.PROPERTY_ACTIVATION_TOKEN + "." + PollenToken.PROPERTY_TOKEN + - " = :token"; - Map<String, Object> params = new HashMap<>(); - params.put("token", token); - return findUniqueOrNull(hql, params); - } } //PollenUserEmailAddressTopiaDao diff --git a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserImpl.java b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserImpl.java index bd84b16b..2ae14757 100644 --- a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserImpl.java +++ b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/PollenUserImpl.java @@ -28,6 +28,6 @@ public class PollenUserImpl extends PollenUserAbstract { @Override public boolean isEmailValidated() { - return getDefaultEmailAddress() == null || getDefaultEmailAddress().getActivationToken() == null; + return getDefaultEmailAddress() == null || getDefaultEmailAddress().isValidated(); } } diff --git a/pollen-persistence/src/main/resources/db/migration/h2/V3_2_0_4__use_JWT_for_validate_email.sql b/pollen-persistence/src/main/resources/db/migration/h2/V3_2_0_4__use_JWT_for_validate_email.sql new file mode 100644 index 00000000..69431683 --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/h2/V3_2_0_4__use_JWT_for_validate_email.sql @@ -0,0 +1,19 @@ +-- use JWT for validate email + +-- add validate field +alter table pollenUserEmailaddress add validated boolean; +update pollenUserEmailaddress set validated = activationtoken is null; + +-- drop activationtoken field +alter table pollenUserEmailaddress drop activationtoken; + +-- delete orphan token +delete from pollentoken where topiaid in ( + select t.topiaid from pollentoken t + left outer join pollenprincipal p + on p.permission = t.topiaid + left outer join sessiontoken s + on s.pollentoken = t.topiaid + where p.topiaid is null + and s.topiaid is null + ); \ No newline at end of file diff --git a/pollen-persistence/src/main/resources/db/migration/postgresql/V3_2_0_4__use_JWT_for_validate_email.sql b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_2_0_4__use_JWT_for_validate_email.sql new file mode 100644 index 00000000..0de3ea85 --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_2_0_4__use_JWT_for_validate_email.sql @@ -0,0 +1,19 @@ +-- use JWT for validate email + +-- add validate field +alter table pollenUserEmailaddress add validated boolean; +update pollenUserEmailaddress set validated = activationtoken is null; + +-- drop activationtoken field +alter table pollenUserEmailaddress drop activationtoken cascade; + +-- delete orphan token +delete from pollentoken where topiaid in ( + select t.topiaid from pollentoken t + left outer join pollenprincipal p + on p.permission = t.topiaid + left outer join sessiontoken s + on s.pollentoken = t.topiaid + where p.topiaid is null + and s.topiaid is null + ); \ No newline at end of file diff --git a/pollen-persistence/src/main/xmi/pollen.properties b/pollen-persistence/src/main/xmi/pollen.properties index ff910a8e..2c99e55e 100644 --- a/pollen-persistence/src/main/xmi/pollen.properties +++ b/pollen-persistence/src/main/xmi/pollen.properties @@ -18,7 +18,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # #L% ###m -model.tagvalue.version=3.2.0.3 +model.tagvalue.version=3.2.0.4 #model.tagValue.notGenerateToString=true #model.tagValue.constantPrefix=PROPERTY_ #model.tagValue.useEnumerationName=true diff --git a/pollen-persistence/src/main/xmi/pollen.zargo b/pollen-persistence/src/main/xmi/pollen.zargo index 419ff5bf..fee50cb2 100644 Binary files a/pollen-persistence/src/main/xmi/pollen.zargo and b/pollen-persistence/src/main/xmi/pollen.zargo differ diff --git a/pollen-services/src/main/config/PollenServices.ini b/pollen-services/src/main/config/PollenServices.ini index 71869494..a708830e 100644 --- a/pollen-services/src/main/config/PollenServices.ini +++ b/pollen-services/src/main/config/PollenServices.ini @@ -11,7 +11,7 @@ final = true description = pollen.configuration.token.secret key = pollen.token.secret type = string -defaultValue = !secret# +defaultValue = IFYD6KLx/GrLZwSFBH5arXMIamWSA8qiVtFImIimDZs= transient = true final = true diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServicesConfig.java b/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServicesConfig.java index 1f611143..b19988dc 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServicesConfig.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/config/PollenServicesConfig.java @@ -35,6 +35,7 @@ import org.chorem.pollen.services.bean.UsersRight; import org.nuiton.config.ApplicationConfig; import org.nuiton.config.ArgumentsParserException; +import java.util.Base64; import java.util.List; import java.util.Locale; import java.util.Map; @@ -171,6 +172,11 @@ public class PollenServicesConfig extends GeneratedPollenServicesConfig { public String getBuildDate() { return get().getOption(BUILD_DATE); - } + } + + public byte[] getTokenSecretBytes() { + String secret = getTokenSecret(); + return Base64.getDecoder().decode(secret); + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/CryptoService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/CryptoService.java index e60e0ec6..109f82f7 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/CryptoService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/CryptoService.java @@ -21,11 +21,15 @@ import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodG import org.chorem.pollen.persistence.entity.PollenUserEmailAddress; import org.chorem.pollen.services.PollenTechnicalException; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.security.GeneralSecurityException; import java.security.SecureRandom; import java.security.Security; import java.util.Date; @@ -40,6 +44,12 @@ public class CryptoService extends PollenServiceSupport { static final SecureRandom SECURE_RANDOM = new SecureRandom(); + static { + if (Security.getProvider(PROVIDER) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + public PGPPublicKey getPublicKey(String email) { PGPPublicKey pgpPublicKey = null; @@ -119,10 +129,6 @@ public class CryptoService extends PollenServiceSupport { protected byte[] encryptMessage(byte[] message, PGPPublicKey pgpPublicKey) throws IOException, PGPException { - if (Security.getProvider(PROVIDER) == null) { - Security.addProvider(new BouncyCastleProvider()); - } - byte[] compressMessage = compressMessage(message); ByteArrayOutputStream bout = new ByteArrayOutputStream(); @@ -180,4 +186,35 @@ public class CryptoService extends PollenServiceSupport { } + public byte[] encryptMessageSymmetric(byte[] message) { + try { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", PROVIDER); + cipher.init(Cipher.ENCRYPT_MODE, getSecretKey()); + return cipher.doFinal(message); + } catch (GeneralSecurityException e) { + throw new PollenTechnicalException("error on encrypt message", e); + } + } + + public byte[] decryptMessageSymmetric(byte[] encryptMessage) { + try { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", PROVIDER); + cipher.init(Cipher.DECRYPT_MODE, getSecretKey()); + return cipher.doFinal(encryptMessage); + } catch (GeneralSecurityException e) { + throw new PollenTechnicalException("error on decrypt message", e); + } + } + + protected SecretKey getSecretKey() { + + byte[] keyBytes = getPollenServiceConfig().getTokenSecretBytes(); + + if (keyBytes.length != 16 && keyBytes.length != 24 && keyBytes.length != 32) { + throw new PollenTechnicalException("keyBytes wrong length for AES key"); + } + + return new SecretKeySpec(keyBytes, "AES"); + } + } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java index 8b576a06..ff31104d 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java @@ -77,10 +77,10 @@ import java.util.Set; */ public class NotificationService extends PollenServiceSupport { - public void onUserCreated(PollenUser user) { + public void onUserCreated(PollenUser user, String token) { if (user.getDefaultEmailAddress() != null) { EmailService emailService = getEmailService(); - UserAccountCreatedEmail email = emailService.newUserAccountCreatedEmail(user); + UserAccountCreatedEmail email = emailService.newUserAccountCreatedEmail(user, token); email.addTo(user.getDefaultEmailAddress().getEmailAddress()); emailService.send(email); commit(); @@ -97,9 +97,9 @@ public class NotificationService extends PollenServiceSupport { } } - public void onResendValidation(PollenUser user, PollenUserEmailAddress emailAddress) { + public void onResendValidation(PollenUser user, PollenUserEmailAddress emailAddress, String token) { EmailService emailService = getEmailService(); - ResendValidationEmail email = emailService.newUserResendValidationEmail(user, emailAddress); + ResendValidationEmail email = emailService.newUserResendValidationEmail(user, token); email.addTo(emailAddress.getEmailAddress()); emailService.send(email); commit(); @@ -135,9 +135,9 @@ public class NotificationService extends PollenServiceSupport { } } - public void onUserEmailAddressAdded(PollenUser user, PollenUserEmailAddress emailAddress) { + public void onUserEmailAddressAdded(PollenUser user, PollenUserEmailAddress emailAddress, String token) { EmailService emailService = getEmailService(); - UserAccountEmailAddressAddedEmail email = emailService.newUserAccountEmailAddressAddedEmail(user, emailAddress); + UserAccountEmailAddressAddedEmail email = emailService.newUserAccountEmailAddressAddedEmail(user, token); email.addTo(emailAddress.getEmailAddress()); emailService.send(email); commit(); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java index e6d4dabb..942fc24c 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java @@ -28,7 +28,6 @@ import org.apache.commons.logging.LogFactory; import org.chorem.pollen.persistence.entity.Comment; import org.chorem.pollen.persistence.entity.PollenPrincipal; import org.chorem.pollen.persistence.entity.PollenResource; -import org.chorem.pollen.persistence.entity.PollenToken; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.PollenUserEmailAddress; import org.chorem.pollen.persistence.entity.ResourceType; @@ -108,7 +107,7 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer PollenUserEmailAddressBean bean = new PollenUserEmailAddressBean(); bean.setEntityId(entity.getTopiaId()); bean.setEmailAddress(entity.getEmailAddress()); - bean.setValidated(entity.getActivationToken() == null); + bean.setValidated(entity.isValidated()); bean.setPgpPublicKey(entity.getPgpPublicKey()); return bean; } @@ -173,7 +172,9 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer PollenUser result = savePollenUser(user); commit(); - getNotificationService().onUserCreated(result); + String token = getSecurityService().generateEmailToken(result.getDefaultEmailAddress()); + + getNotificationService().onUserCreated(result, token); return PollenEntityRef.of(result); @@ -253,13 +254,13 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer checkNotNull(token); PollenUser user = getUser0(userId); - PollenUserEmailAddress emailAddress = getPollenUserEmailAddressDao().findEmailAddressByToken(token); + PollenUserEmailAddress emailAddress = getSecurityService().getEmailAdresseFromToken(token); if (emailAddress == null || !user.containsEmailAddresses(emailAddress)) { throw new PollenInvalidEmailActivationTokenException(); } // reset token in database - emailAddress.setActivationToken(null); + emailAddress.setValidated(true); commit(); @@ -280,7 +281,7 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer } // reset token in database - emailAddress.setActivationToken(null); + emailAddress.setValidated(true); commit(); @@ -297,12 +298,12 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer } PollenUser user = getPollenUserDao().forEmailAddressesContains(userEmailAddress).findUnique(); - if (userEmailAddress.getActivationToken() == null) { - userEmailAddress.setActivationToken(getSecurityService().generateNewToken()); - commit(); - } + userEmailAddress.setValidated(false); + commit(); - getNotificationService().onResendValidation(user, userEmailAddress); + String token = getSecurityService().generateEmailToken(userEmailAddress); + + getNotificationService().onResendValidation(user, userEmailAddress, token); } @@ -321,7 +322,7 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer PollenUser admin = savePollenUser(adminBean); admin.setAdministrator(true); - admin.getDefaultEmailAddress().setActivationToken(null); + admin.getDefaultEmailAddress().setValidated(true); commit(); } @@ -376,12 +377,13 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer PollenUserEmailAddress address = getPollenUserEmailAddressDao().create(); address.setEmailAddress(emailAddress); - PollenToken emailActivation = getSecurityService().generateNewToken(); - address.setActivationToken(emailActivation); + address.setValidated(false); user.addEmailAddresses(address); commit(); - getNotificationService().onUserEmailAddressAdded(user, address); + String token = getSecurityService().generateEmailToken(address); + + getNotificationService().onUserEmailAddressAdded(user, address, token); return PollenEntityRef.of(address); } @@ -411,7 +413,7 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer checkNotNull(emailAddressId); PollenUserEmailAddress emailAddress = user.getEmailAddressesByTopiaId(emailAddressId); checkNotNull(emailAddress); - if (emailAddress.getActivationToken() != null) { + if (!emailAddress.isValidated()) { throw new PollenEmailNotValidatedException(); } user.setDefaultEmailAddress(emailAddress); @@ -478,8 +480,6 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer } else { - PollenToken emailActivation = getSecurityService().generateNewToken(); - toSave = getPollenUserDao().create(); PollenUserEmailAddressBean emailAddress = user.getDefaultEmailAddress(); @@ -487,7 +487,7 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer PollenUserEmailAddress defaultEmailAddress = getPollenUserEmailAddressDao().create(); String cleanMail = getCleanMail(emailAddress.getEmailAddress()); defaultEmailAddress.setEmailAddress(cleanMail); - defaultEmailAddress.setActivationToken(emailActivation); + defaultEmailAddress.setValidated(false); toSave.addEmailAddresses(defaultEmailAddress); toSave.setDefaultEmailAddress(defaultEmailAddress); } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java index 541cbb4a..a92d54a5 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java @@ -45,7 +45,6 @@ import org.chorem.pollen.persistence.entity.Poll; import org.chorem.pollen.persistence.entity.PollenPrincipal; import org.chorem.pollen.persistence.entity.PollenResource; import org.chorem.pollen.persistence.entity.PollenUser; -import org.chorem.pollen.persistence.entity.PollenUserEmailAddress; import org.chorem.pollen.persistence.entity.Report; import org.chorem.pollen.persistence.entity.UserCredential; import org.chorem.pollen.persistence.entity.Vote; @@ -248,14 +247,14 @@ public class EmailService extends PollenServiceSupport { return email; } - public UserAccountCreatedEmail newUserAccountCreatedEmail(PollenUser user) { + public UserAccountCreatedEmail newUserAccountCreatedEmail(PollenUser user, String token) { UserAccountCreatedEmail email = new UserAccountCreatedEmail(getLocale(), getTimeZone()); email.setUser(user); PollenEntityId<PollenUser> userId = getPollenEntityId(user); email.setValidateUrl(getPollenUIUrlRenderService().getUserValidateUrl(getUIContext().getUserValidateUrl(), userId.getReducedId(), - user.getDefaultEmailAddress().getActivationToken().getToken())); + token)); return email; } @@ -282,13 +281,13 @@ public class EmailService extends PollenServiceSupport { } public UserAccountEmailAddressAddedEmail newUserAccountEmailAddressAddedEmail(PollenUser user, - PollenUserEmailAddress emailAddress) { + String token) { UserAccountEmailAddressAddedEmail email = new UserAccountEmailAddressAddedEmail(getLocale(), getTimeZone()); email.setUser(user); PollenEntityId<PollenUser> userId = getPollenEntityId(user); email.setValidateUrl(getPollenUIUrlRenderService().getUserValidateUrl(getUIContext().getUserValidateUrl(), userId.getReducedId(), - emailAddress.getActivationToken().getToken())); + token)); return email; } @@ -299,14 +298,14 @@ public class EmailService extends PollenServiceSupport { return email; } - public ResendValidationEmail newUserResendValidationEmail(PollenUser user, PollenUserEmailAddress emailAddress) { + public ResendValidationEmail newUserResendValidationEmail(PollenUser user, String token) { ResendValidationEmail email = new ResendValidationEmail(getLocale(), getTimeZone()); email.setUser(user); PollenEntityId<PollenUser> userId = getPollenEntityId(user); email.setValidateUrl(getPollenUIUrlRenderService().getUserValidateUrl(getUIContext().getUserValidateUrl(), userId.getReducedId(), - emailAddress.getActivationToken().getToken())); + token)); return email; } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java index 0a9903a9..58dc2de3 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java @@ -27,6 +27,7 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; import com.google.common.base.Preconditions; +import com.google.common.primitives.Longs; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -48,14 +49,15 @@ import org.chorem.pollen.persistence.entity.VoteVisibility; import org.chorem.pollen.persistence.entity.VoterList; import org.chorem.pollen.persistence.entity.VoterListMember; import org.chorem.pollen.services.PollenServiceContext; -import org.chorem.pollen.services.PollenTechnicalException; import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.bean.UsersRight; import org.chorem.pollen.services.service.PollService; import org.chorem.pollen.services.service.PollenServiceSupport; import org.nuiton.topia.persistence.TopiaNoResultException; -import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Base64; import java.util.Calendar; import java.util.Date; import java.util.Objects; @@ -249,12 +251,48 @@ public class SecurityService extends PollenServiceSupport { } protected Algorithm getAlgorithm() { - String secret = getPollenServiceConfig().getTokenSecret(); - try { - return Algorithm.HMAC256(secret); - } catch (UnsupportedEncodingException e) { - throw new PollenTechnicalException(e); + byte[] secret = getPollenServiceConfig().getTokenSecretBytes(); + return Algorithm.HMAC256(secret); + } + + public String generateEmailToken(PollenUserEmailAddress email) { + long expireDate = getNow().getTime() + getPollenServiceConfig().getTokenTimeout() * 1000; + byte[] bytesEmail = email.getEmailAddress().getBytes(); + + + ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES + bytesEmail.length); + buffer.putLong(expireDate); + buffer.put(bytesEmail); + byte[] message = buffer.array(); + + byte[] encryptMessage = getCryptoService().encryptMessageSymmetric(message); + + String token = Base64.getUrlEncoder().encodeToString(encryptMessage); + return token; + } + + public PollenUserEmailAddress getEmailAdresseFromToken(String token) { + PollenUserEmailAddress pollenUserEmailAddress = null; + + if (StringUtils.isNotBlank(token)) { + + byte[] encryptMessage = Base64.getUrlDecoder().decode(token); + + byte[] message = getCryptoService().decryptMessageSymmetric(encryptMessage); + + byte[] bytesExpireDate = Arrays.copyOfRange(message, 0, Long.BYTES); + byte[] bytesEmail = Arrays.copyOfRange(message, Long.BYTES, message.length); + + long expireDate = Longs.fromByteArray(bytesExpireDate); + String emailAdresse = new String(bytesEmail); + + if (getNow().getTime() <= expireDate) { + pollenUserEmailAddress = getPollenUserEmailAddressDao().forEmailAddressEquals(emailAdresse).findUniqueOrNull(); + + } + } + return pollenUserEmailAddress; } public PollenToken generateNewToken() { @@ -377,7 +415,7 @@ public class SecurityService extends PollenServiceSupport { protected boolean isConnectedUserAcceptEmailSuffix(String suffix) { return getConnectedUser().getEmailAddresses().stream() - .filter(email -> email.getActivationToken() == null) // email Validate + .filter(PollenUserEmailAddress::isValidated) // email Validate .map(PollenUserEmailAddress::getEmailAddress) .anyMatch(email -> email.endsWith(suffix)); } diff --git a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties index 28e65d98..dc059689 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties @@ -32,7 +32,7 @@ pollen.configuration.smtpFrom=Smtp From pollen.configuration.smtpPort=Smtp Port pollen.configuration.smtpWait=Time between two send mail to smtp pollen.configuration.token.issue=Producer name for authentification tokens -pollen.configuration.token.secret=secret key for authentification tokens +pollen.configuration.token.secret=secret key for authentification tokens (encoding in base 64) (16, 24 or 32 bytes) pollen.configuration.token.timeout=Inactivity delay before invalidate the session of a user (in seconds) pollen.configuration.userConnectedRequired=Only connected users can be access on application pollen.configuration.usersCanCreatePoll=Wich user can create Poll ("All_USERS", "USERS_CONNECTED" or "USERS_SELECTED") diff --git a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties index 6407eb33..95a8f648 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties @@ -32,7 +32,7 @@ pollen.configuration.smtpFrom=Expéditeur pollen.configuration.smtpPort=Port smtp pollen.configuration.smtpWait=Intervalle de temps entre deux envois de mail au SMTP pollen.configuration.token.issue=Nom du producteur de jeton d'authentification -pollen.configuration.token.secret=Clé secret pour chiffer le jetons d'authnetification +pollen.configuration.token.secret=Clé secret pour chiffer le jetons d'authnetification (encodé en base 64) (16, 24 ou 32 bytes) pollen.configuration.token.timeout=Temps autorisé d'inactivité avant d'invalider une session utilisateur (en secondes) pollen.configuration.userConnectedRequired=Seul les utilisateurs connectés peuvent accéder à l'application pollen.configuration.usersCanCreatePoll=Quels utilisateurs peuvent créer des sondages ("All_USERS", "USERS_CONNECTED" ou "USERS_SELECTED") -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
participants (1)
-
chorem.org scm