From 3eb86b41f2166c28e8f2384f80d3849d0da0c552 Mon Sep 17 00:00:00 2001 From: jensp Date: Wed, 30 Mar 2016 17:23:09 +0000 Subject: [PATCH] CCM NG: OneTimeAuth system, used for PasswordRecover, Account activation and email verification git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3967 8810af33-2d31-482b-a856-94f89814c4df --- ccm-core/pom.xml | 2 + .../com/arsdigita/ui/login/LoginServlet.java | 2 + .../libreccm/security/ChallengeManager.java | 70 ++++++++ .../libreccm/security/OneTimeAuthConfig.java | 87 +++++++++ .../libreccm/security/OneTimeAuthManager.java | 61 +++++++ .../libreccm/security/OneTimeAuthToken.java | 169 ++++++++++++++++++ .../security/OneTimeAuthTokenPurpose.java | 32 ++++ .../resources/META-INF/persistence-ddl.xml | 42 +++++ .../V7_0_0_1__create_one_time_auth_tokens.sql | 13 ++ .../V7_0_0_1__create_one_time_auth_tokens.sql | 13 ++ .../security/EqualsAndHashCodeTest.java | 1 + .../org/libreccm/security/ToStringTest.java | 1 + .../scripts/create_ccm_core_schema.sql | 24 ++- .../scripts/create_ccm_core_schema.sql | 25 ++- 14 files changed, 531 insertions(+), 11 deletions(-) create mode 100644 ccm-core/src/main/java/org/libreccm/security/ChallengeManager.java create mode 100644 ccm-core/src/main/java/org/libreccm/security/OneTimeAuthConfig.java create mode 100644 ccm-core/src/main/java/org/libreccm/security/OneTimeAuthManager.java create mode 100644 ccm-core/src/main/java/org/libreccm/security/OneTimeAuthToken.java create mode 100644 ccm-core/src/main/java/org/libreccm/security/OneTimeAuthTokenPurpose.java create mode 100644 ccm-core/src/main/resources/META-INF/persistence-ddl.xml create mode 100644 ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/h2/V7_0_0_1__create_one_time_auth_tokens.sql create mode 100644 ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/pgsql/V7_0_0_1__create_one_time_auth_tokens.sql diff --git a/ccm-core/pom.xml b/ccm-core/pom.xml index 219629e18..a59792f32 100644 --- a/ccm-core/pom.xml +++ b/ccm-core/pom.xml @@ -330,6 +330,7 @@ org.libreccm.web org.libreccm.workflow + ${basedir}/src/main/resources/META-INF/persistence-ddl.xml true @@ -656,6 +657,7 @@ org.libreccm true + ${basedir}/src/main/resources/META-INF/persistence-ddl.xml diff --git a/ccm-core/src/main/java/com/arsdigita/ui/login/LoginServlet.java b/ccm-core/src/main/java/com/arsdigita/ui/login/LoginServlet.java index 4723a9755..354b369c6 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/login/LoginServlet.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/login/LoginServlet.java @@ -98,6 +98,8 @@ public class LoginServlet extends BebopApplicationServlet { public static final String RECOVER_USER_PASSWORD_PATH_INFO = "/recover-password/"; + public static final String VERIFY_EMAIL = "/verify-email/"; + /** * PathInfo into the Login application to access the (optional) newUser * page. Ends with "/" because it is a servlet/directory diff --git a/ccm-core/src/main/java/org/libreccm/security/ChallengeManager.java b/ccm-core/src/main/java/org/libreccm/security/ChallengeManager.java new file mode 100644 index 000000000..ed5c121bc --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/security/ChallengeManager.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security; + +import javax.enterprise.context.RequestScoped; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +public class ChallengeManager { + + public String createEmailVerification(final User user) { + throw new UnsupportedOperationException(); + } + + public void sendEmailVerification(final User user) { + throw new UnsupportedOperationException(); + } + + public void finishEmailVerification(final User user, + final String submittedToken) { + throw new UnsupportedOperationException(); + } + + public String createEmailActivation(final User user) { + throw new UnsupportedOperationException(); + } + + public void sendUserActivation(final User user) { + throw new UnsupportedOperationException(); + } + + public void finishUserActivation(final User user, + final String submittedToken) { + throw new UnsupportedOperationException(); + } + + public void sendPasswordRecover(final User user) { + throw new UnsupportedOperationException(); + } + + public void sendPasswordRevover(final User user) { + throw new UnsupportedOperationException(); + } + + public void finishPasswordRecover(final User user, + final String submittedToken, + final String newPassword) { + throw new UnsupportedOperationException(); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/security/OneTimeAuthConfig.java b/ccm-core/src/main/java/org/libreccm/security/OneTimeAuthConfig.java new file mode 100644 index 000000000..697e5d09b --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/security/OneTimeAuthConfig.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.configuration.Configuration; +import org.libreccm.configuration.ConfigurationManager; +import org.libreccm.configuration.Setting; + +/** + * + * @author Jens Pelzetter + */ +@Configuration +public final class OneTimeAuthConfig { + + /** + * How long is a OneTimeAuthToken valid (in seconds)? + */ + @Setting + private int tokenValid = 3600; + + public static OneTimeAuthConfig getConfig() { + final ConfigurationManager confManager = CdiUtil.createCdiUtil() + .findBean(ConfigurationManager.class); + return confManager.findConfiguration(OneTimeAuthConfig.class); + } + + public OneTimeAuthConfig() { + super(); + } + + public int getTokenValid() { + return tokenValid; + } + + public void setTokenValid(final int tokenValid) { + this.tokenValid = tokenValid; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 79 * hash + tokenValid; + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof OneTimeAuthConfig)) { + return false; + } + final OneTimeAuthConfig other = (OneTimeAuthConfig) obj; + return this.tokenValid == other.getTokenValid(); + } + + @Override + public String toString() { + return String.format("%s{ " + + "tokenValid = %d" + + " }", + tokenValid); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/security/OneTimeAuthManager.java b/ccm-core/src/main/java/org/libreccm/security/OneTimeAuthManager.java new file mode 100644 index 000000000..6969ba17a --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/security/OneTimeAuthManager.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security; + +import org.libreccm.configuration.ConfigurationManager; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.persistence.EntityManager; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +public class OneTimeAuthManager { + + @Inject + private EntityManager entityManager; + + @Inject + private ConfigurationManager configurationManager; + + public OneTimeAuthToken createForUser(final User user) { + throw new UnsupportedOperationException(); + } + + public OneTimeAuthToken retrieveForUser(final User user) { + throw new UnsupportedOperationException(); + } + + public boolean validTokenExistsForUser(final User user) { + throw new UnsupportedOperationException(); + } + + public boolean isValid(final OneTimeAuthToken token) { + throw new UnsupportedOperationException(); + } + + public void invalidate(final OneTimeAuthToken token) { + throw new UnsupportedOperationException(); + } + + +} diff --git a/ccm-core/src/main/java/org/libreccm/security/OneTimeAuthToken.java b/ccm-core/src/main/java/org/libreccm/security/OneTimeAuthToken.java new file mode 100644 index 000000000..e1267be53 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/security/OneTimeAuthToken.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2016 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; +import java.util.Objects; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +/** + * + * @author Jens Pelzetter + */ +@Entity +@Table(name = "ONE_TIME_AUTH_TOKENS") +public class OneTimeAuthToken implements Serializable { + + private static final long serialVersionUID = -9088185274208292873L; + + @Id + @Column(name = "TOKEN_ID") + @GeneratedValue(strategy = GenerationType.AUTO) + private long tokenId; + + @OneToOne + @JoinColumn(name = "USER_ID") + private User user; + + @Column(name = "TOKEN", length = 255) + private String token; + + @Column(name = "VALID_UNIT") + @Temporal(TemporalType.DATE) + private Date validUntil; + + @Column(name = "PURPOSE") + @Enumerated(EnumType.STRING) + private OneTimeAuthTokenPurpose purpose; + + public long getTokenId() { + return tokenId; + } + + protected void setTokenId(final long tokenId) { + this.tokenId = tokenId; + } + + public User getUser() { + return user; + } + + public void setUser(final User user) { + this.user = user; + } + + public String getToken() { + return token; + } + + public void setToken(final String token) { + this.token = token; + } + + public Date getValidUntil() { + return new Date(validUntil.getTime()); + } + + public void setValidUntil(final Date validUntil) { + this.validUntil = new Date(validUntil.getTime()); + } + + public OneTimeAuthTokenPurpose getPurpose() { + return purpose; + } + + public void setPurpose(final OneTimeAuthTokenPurpose purpose) { + this.purpose = purpose; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 97 * hash + Objects.hashCode(user); + hash = 97 * hash + Objects.hashCode(token); + hash = 97 * hash + Objects.hashCode(validUntil); + hash = 97 * hash + Objects.hashCode(purpose); + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof OneTimeAuthToken)) { + return false; + } + final OneTimeAuthToken other = (OneTimeAuthToken) obj; + if (!other.canEqual(this)) { + return false; + } + + if (!Objects.equals(token, other.getToken())) { + return false; + } + if (!Objects.equals(user, other.getUser())) { + return false; + } + if (!Objects.equals(validUntil, other.getValidUntil())) { + return false; + } + return purpose == other.getPurpose(); + } + + public boolean canEqual(final Object obj) { + return obj instanceof OneTimeAuthToken; + } + + @Override + public final String toString() { + return toString(""); + } + + public String toString(final String data) { + return String.format("%s{ " + + "tokenId = %d, " + + "user = { %s }, " + + "validUnit = %tF %Jens Pelzetter + */ +public enum OneTimeAuthTokenPurpose { + + ACCOUNT_ACTIVATION, + EMAIL_VERIFICATION, + RECOVER_PASSWORD + + +} diff --git a/ccm-core/src/main/resources/META-INF/persistence-ddl.xml b/ccm-core/src/main/resources/META-INF/persistence-ddl.xml new file mode 100644 index 000000000..a98d422e3 --- /dev/null +++ b/ccm-core/src/main/resources/META-INF/persistence-ddl.xml @@ -0,0 +1,42 @@ + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + + java:/comp/env/jdbc/libreccm/db + + + + + + + + + + + + + + + diff --git a/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/h2/V7_0_0_1__create_one_time_auth_tokens.sql b/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/h2/V7_0_0_1__create_one_time_auth_tokens.sql new file mode 100644 index 000000000..196943f4f --- /dev/null +++ b/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/h2/V7_0_0_1__create_one_time_auth_tokens.sql @@ -0,0 +1,13 @@ +create table ONE_TIME_AUTH_TOKENS ( + TOKEN_ID bigint not null, + PURPOSE varchar(255), + TOKEN varchar(255), + VALID_UNIT date, + USER_ID bigint, + primary key (TOKEN_ID) + ); + +alter table ONE_TIME_AUTH_TOKENS + add constraint FK_fvr3t6w3nsm3u29mjuh4tplno + foreign key (USER_ID) + references CCM_CORE.USERS; \ No newline at end of file diff --git a/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/pgsql/V7_0_0_1__create_one_time_auth_tokens.sql b/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/pgsql/V7_0_0_1__create_one_time_auth_tokens.sql new file mode 100644 index 000000000..fbcd26118 --- /dev/null +++ b/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/pgsql/V7_0_0_1__create_one_time_auth_tokens.sql @@ -0,0 +1,13 @@ + create table ONE_TIME_AUTH_TOKENS ( + TOKEN_ID int8 not null, + PURPOSE varchar(255), + TOKEN varchar(255), + VALID_UNIT date, + USER_ID int8, + primary key (TOKEN_ID) + ); + + alter table ONE_TIME_AUTH_TOKENS + add constraint FK_fvr3t6w3nsm3u29mjuh4tplno + foreign key (USER_ID) + references CCM_CORE.USERS; \ No newline at end of file diff --git a/ccm-core/src/test/java/org/libreccm/security/EqualsAndHashCodeTest.java b/ccm-core/src/test/java/org/libreccm/security/EqualsAndHashCodeTest.java index 96b988f7e..5256c8e42 100644 --- a/ccm-core/src/test/java/org/libreccm/security/EqualsAndHashCodeTest.java +++ b/ccm-core/src/test/java/org/libreccm/security/EqualsAndHashCodeTest.java @@ -42,6 +42,7 @@ public class EqualsAndHashCodeTest extends EqualsVerifier { GroupMembership.class, Party.class, Permission.class, + OneTimeAuthToken.class, Role.class, RoleMembership.class, User.class diff --git a/ccm-core/src/test/java/org/libreccm/security/ToStringTest.java b/ccm-core/src/test/java/org/libreccm/security/ToStringTest.java index b5e057af0..1055edd78 100644 --- a/ccm-core/src/test/java/org/libreccm/security/ToStringTest.java +++ b/ccm-core/src/test/java/org/libreccm/security/ToStringTest.java @@ -41,6 +41,7 @@ public class ToStringTest extends ToStringVerifier { Group.class, GroupMembership.class, Party.class, + OneTimeAuthToken.class, Permission.class, Role.class, RoleMembership.class, diff --git a/ccm-core/src/test/resources-wildfly8-remote-h2-mem/scripts/create_ccm_core_schema.sql b/ccm-core/src/test/resources-wildfly8-remote-h2-mem/scripts/create_ccm_core_schema.sql index ae332dcfa..95ef56c77 100644 --- a/ccm-core/src/test/resources-wildfly8-remote-h2-mem/scripts/create_ccm_core_schema.sql +++ b/ccm-core/src/test/resources-wildfly8-remote-h2-mem/scripts/create_ccm_core_schema.sql @@ -629,17 +629,26 @@ CREATE SCHEMA ccm_core; primary key (TASK_ID) ); - alter table CCM_CORE.CATEGORY_DOMAINS - add constraint UK_mb1riernf8a88u3mwl0bgfj8y unique (DOMAIN_KEY); + create table ONE_TIME_AUTH_TOKENS ( + TOKEN_ID bigint not null, + PURPOSE varchar(255), + TOKEN varchar(255), + VALID_UNIT date, + USER_ID bigint, + primary key (TOKEN_ID) + ); alter table CCM_CORE.CATEGORY_DOMAINS - add constraint UK_i1xqotjvml7i6ro2jq22fxf5g unique (URI); + add constraint UK_mb1riernf8a88u3mwl0bgfj8y unique (DOMAIN_KEY); + + alter table CCM_CORE.CATEGORY_DOMAINS + add constraint UK_i1xqotjvml7i6ro2jq22fxf5g unique (URI); alter table CCM_CORE.HOSTS - add constraint UK_9ramlv6uxwt13v0wj7q0tucsx unique (SERVER_NAME, SERVER_PORT); + add constraint UK_9ramlv6uxwt13v0wj7q0tucsx unique (SERVER_NAME, SERVER_PORT); alter table CCM_CORE.INSTALLED_MODULES - add constraint UK_11imwgfojyi4hpr18uw9g3jvx unique (MODULE_CLASS_NAME); + add constraint UK_11imwgfojyi4hpr18uw9g3jvx unique (MODULE_CLASS_NAME); alter table CCM_CORE.APPLICATIONS add constraint FK_sn1sqtx94nhxgv282ymoqiock @@ -1131,4 +1140,9 @@ CREATE SCHEMA ccm_core; foreign key (WORKFLOW_ID) references CCM_CORE.WORKFLOWS; + alter table ONE_TIME_AUTH_TOKENS + add constraint FK_fvr3t6w3nsm3u29mjuh4tplno + foreign key (USER_ID) + references CCM_CORE.USERS; + create sequence hibernate_sequence start with 1 increment by 1; \ No newline at end of file diff --git a/ccm-core/src/test/resources-wildfly8-remote-pgsql/scripts/create_ccm_core_schema.sql b/ccm-core/src/test/resources-wildfly8-remote-pgsql/scripts/create_ccm_core_schema.sql index 4587fc532..acca5129c 100644 --- a/ccm-core/src/test/resources-wildfly8-remote-pgsql/scripts/create_ccm_core_schema.sql +++ b/ccm-core/src/test/resources-wildfly8-remote-pgsql/scripts/create_ccm_core_schema.sql @@ -4,7 +4,6 @@ DROP SEQUENCE IF EXISTS hibernate_sequence; CREATE SCHEMA ccm_core; - create table CCM_CORE.APPLICATIONS ( APPLICATION_TYPE varchar(1024) not null, PRIMARY_URL varchar(1024) not null, @@ -630,17 +629,26 @@ CREATE SCHEMA ccm_core; primary key (TASK_ID) ); - alter table CCM_CORE.CATEGORY_DOMAINS - add constraint UK_mb1riernf8a88u3mwl0bgfj8y unique (DOMAIN_KEY); + create table ONE_TIME_AUTH_TOKENS ( + TOKEN_ID int8 not null, + PURPOSE varchar(255), + TOKEN varchar(255), + VALID_UNIT date, + USER_ID int8, + primary key (TOKEN_ID) + ); alter table CCM_CORE.CATEGORY_DOMAINS - add constraint UK_i1xqotjvml7i6ro2jq22fxf5g unique (URI); + add constraint UK_mb1riernf8a88u3mwl0bgfj8y unique (DOMAIN_KEY); + + alter table CCM_CORE.CATEGORY_DOMAINS + add constraint UK_i1xqotjvml7i6ro2jq22fxf5g unique (URI); alter table CCM_CORE.HOSTS - add constraint UK_9ramlv6uxwt13v0wj7q0tucsx unique (SERVER_NAME, SERVER_PORT); + add constraint UK_9ramlv6uxwt13v0wj7q0tucsx unique (SERVER_NAME, SERVER_PORT); alter table CCM_CORE.INSTALLED_MODULES - add constraint UK_11imwgfojyi4hpr18uw9g3jvx unique (MODULE_CLASS_NAME); + add constraint UK_11imwgfojyi4hpr18uw9g3jvx unique (MODULE_CLASS_NAME); alter table CCM_CORE.APPLICATIONS add constraint FK_sn1sqtx94nhxgv282ymoqiock @@ -1132,4 +1140,9 @@ CREATE SCHEMA ccm_core; foreign key (WORKFLOW_ID) references CCM_CORE.WORKFLOWS; + alter table ONE_TIME_AUTH_TOKENS + add constraint FK_fvr3t6w3nsm3u29mjuh4tplno + foreign key (USER_ID) + references CCM_CORE.USERS; + create sequence hibernate_sequence start 1 increment 1; \ No newline at end of file