├── .env ├── .github └── workflows │ └── maven.yml ├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── 1-init.sql ├── Dockerfile ├── LICENSE ├── README.md ├── ddd_common-v1.0.0.jar ├── docker-compose-ci.yml ├── docker-compose.yml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── tomo │ │ └── mcauthentication │ │ ├── McAuthenticationApplication.java │ │ ├── application │ │ ├── BaseMapper.java │ │ ├── McAuthenticationEventHandler.java │ │ ├── authentication │ │ │ ├── BaseLoginCommandHandler.java │ │ │ ├── EmailLoginCommandHandler.java │ │ │ ├── FacebookLoginCommandHandler.java │ │ │ ├── GoogleLoginCommandHandler.java │ │ │ ├── LogoutCommandHandler.java │ │ │ ├── SessionAuthenticationCommandHandler.java │ │ │ ├── command │ │ │ │ ├── BaseLoginCommand.java │ │ │ │ ├── EmailLoginCommand.java │ │ │ │ ├── FacebookLoginCommand.java │ │ │ │ ├── GoogleLoginCommand.java │ │ │ │ ├── LogoutCommand.java │ │ │ │ └── SessionAuthenticationCommand.java │ │ │ └── dto │ │ │ │ ├── RecoveryPasswordDto.java │ │ │ │ └── SessionDto.java │ │ ├── configuration │ │ │ ├── AbstractVoidyCommandHandler.java │ │ │ ├── CommandHandler.java │ │ │ ├── QueryHandler.java │ │ │ └── RequestHandler.java │ │ ├── contracts │ │ │ ├── BaseCommand.java │ │ │ ├── BaseQuery.java │ │ │ ├── BaseRequest.java │ │ │ ├── Command.java │ │ │ ├── Identifiable.java │ │ │ ├── McAuthenticationModule.java │ │ │ ├── Query.java │ │ │ ├── Request.java │ │ │ ├── Response.java │ │ │ ├── Voidy.java │ │ │ └── security │ │ │ │ ├── AbstractAuthenticateCommand.java │ │ │ │ ├── AbstractAuthenticateQuery.java │ │ │ │ ├── AbstractAuthenticateRequest.java │ │ │ │ ├── AbstractAuthorizeCommand.java │ │ │ │ ├── AbstractAuthorizeQuery.java │ │ │ │ ├── AbstractAuthorizeRequest.java │ │ │ │ ├── Authenticate.java │ │ │ │ └── Authorize.java │ │ ├── recovery │ │ │ ├── CreatePasswordRecoveryCodeCommandHandler.java │ │ │ ├── GetUserRegistrationWithRecoveryCodeQueryHandler.java │ │ │ ├── PasswordRecoveryCodeCreatedEventHandler.java │ │ │ ├── SendPasswordRecoveryEmailCommandHandler.java │ │ │ ├── UpdatePasswordWithRecoveryCodeCommandHandler.java │ │ │ ├── command │ │ │ │ ├── CreatePasswordRecoveryCodeCommand.java │ │ │ │ ├── SendPasswordRecoveryEmailCommand.java │ │ │ │ └── UpdatePasswordWithRecoveryCodeCommand.java │ │ │ └── dto │ │ │ │ └── GetUserRegistrationWithRecoveryCodeQuery.java │ │ ├── registration │ │ │ ├── ChangePasswordCommandHandler.java │ │ │ ├── ConfirmUserRegistrationCommandHandler.java │ │ │ ├── GetUserRegistrationQueryHandler.java │ │ │ ├── NewUserRegisteredEventHandler.java │ │ │ ├── RegisterNewUserCommandHandler.java │ │ │ ├── SendRegistrationConfirmationEmailCommandHandler.java │ │ │ ├── command │ │ │ │ ├── ChangePasswordCommand.java │ │ │ │ ├── ConfirmUserRegistrationCommand.java │ │ │ │ ├── RegisterNewUserCommand.java │ │ │ │ └── SendRegistrationConfirmationEmailCommand.java │ │ │ ├── dto │ │ │ │ └── UserRegistrationDto.java │ │ │ └── query │ │ │ │ └── GetUserRegistrationQuery.java │ │ └── users │ │ │ ├── ChangeUserDetailsCommandHandler.java │ │ │ ├── GetUserQueryHandler.java │ │ │ ├── command │ │ │ └── ChangeUserDetailsCommand.java │ │ │ ├── dto │ │ │ └── BaseUserDto.java │ │ │ └── query │ │ │ └── GetUserQuery.java │ │ ├── domain │ │ ├── DomainRegistry.java │ │ ├── EncryptionService.java │ │ ├── oauth2 │ │ │ ├── OAuth2Authentication.java │ │ │ ├── OAuth2Principal.java │ │ │ └── OAuth2Service.java │ │ ├── registration │ │ │ ├── EmailAuthenticationService.java │ │ │ ├── PasswordService.java │ │ │ ├── UserRegistration.java │ │ │ ├── UserRegistrationId.java │ │ │ ├── UserRegistrationRepository.java │ │ │ ├── UserRegistrationStatus.java │ │ │ ├── UsersCounter.java │ │ │ ├── events │ │ │ │ ├── PasswordChanged.java │ │ │ │ ├── PasswordRecovered.java │ │ │ │ ├── PasswordRecoveryCodeCreated.java │ │ │ │ ├── UserRegistrationConfirmed.java │ │ │ │ └── UserRegistrationRequested.java │ │ │ └── rules │ │ │ │ ├── PasswordRecoveryCodeShouldBeExpiredOrNull.java │ │ │ │ ├── PasswordRecoveryCodeShouldNotExpired.java │ │ │ │ ├── PasswordsMustMatch.java │ │ │ │ ├── RecoveryCodeMustMatch.java │ │ │ │ ├── UserRegistrationCannotBeConfirmedAfterExpiration.java │ │ │ │ ├── UserRegistrationCannotBeConfirmedMoreThanOnce.java │ │ │ │ ├── UserRegistrationMustBeConfirmed.java │ │ │ │ └── UserRegistrationMustBeUnique.java │ │ ├── session │ │ │ ├── JwtTokenProvider.java │ │ │ ├── Session.java │ │ │ ├── SessionAuthenticationService.java │ │ │ ├── SessionId.java │ │ │ ├── SessionRepository.java │ │ │ ├── TokenProvider.java │ │ │ ├── events │ │ │ │ └── SessionCreated.java │ │ │ └── rule │ │ │ │ └── SessionCannotBeExpiredWhenRefreshTokenIsMissing.java │ │ └── users │ │ │ ├── EmailLogin.java │ │ │ ├── User.java │ │ │ ├── UserId.java │ │ │ ├── UserRepository.java │ │ │ ├── events │ │ │ ├── UserCreated.java │ │ │ └── UserNameChanged.java │ │ │ └── rules │ │ │ └── UserEmailMustBeUnique.java │ │ └── infrastructure │ │ ├── McAuthenticationModuleExecutor.java │ │ ├── http │ │ └── oauth2 │ │ │ ├── AbstractOAuth2Authentication.java │ │ │ ├── CustomOAuth2UserService.java │ │ │ ├── FacebookOAuth2Authentication.java │ │ │ ├── GoogleOAuth2Authentication.java │ │ │ └── user │ │ │ ├── FacebookOAuth2UserInfo.java │ │ │ ├── GoogleOAuth2UserInfo.java │ │ │ ├── OAuth2UserInfo.java │ │ │ └── OAuth2UserInfoFactory.java │ │ ├── persistence │ │ ├── BaseJpaAdapter.java │ │ ├── SessionJpaRepository.java │ │ ├── SessionRepositoryJpaAdapter.java │ │ ├── UserJpaRepository.java │ │ ├── UserRegistrationJpaRepository.java │ │ ├── UserRegistrationJpaRepositoryAdapter.java │ │ └── UserRepositoryJpaAdapter.java │ │ ├── processing │ │ ├── ErrorCommandHandlerDecorator.java │ │ ├── LoggingCommandHandlerDecorator.java │ │ ├── LoggingQueryHandlerDecorator.java │ │ ├── PipelineBuilder.java │ │ └── builder │ │ │ ├── AbstractPipelineBuilder.java │ │ │ ├── CommandHandlerPipelineBuilder.java │ │ │ └── QueryHandlerPipelineBuilder.java │ │ ├── service │ │ └── MD5EncryptionService.java │ │ ├── springboot │ │ ├── configuration │ │ │ ├── AppConfig.java │ │ │ ├── AppProperties.java │ │ │ ├── GUIProperties.java │ │ │ ├── MessageProperties.java │ │ │ ├── SecurityConfig.java │ │ │ ├── SwaggerConfig.java │ │ │ └── SwaggerUiWebMvcConfigurer.java │ │ ├── controller │ │ │ ├── AbstractController.java │ │ │ ├── AuthenticationController.java │ │ │ ├── RegistrationController.java │ │ │ ├── RestApiRoutes.java │ │ │ └── UserController.java │ │ ├── filter │ │ │ └── TokenAuthenticationFilter.java │ │ └── security │ │ │ ├── CurrentUser.java │ │ │ ├── OAuth2AuthenticationFailureHandler.java │ │ │ ├── OAuth2AuthenticationSuccessHandler.java │ │ │ ├── UserAuthPrincipal.java │ │ │ └── UserAuthToken.java │ │ └── util │ │ └── CookieUtils.java └── resources │ ├── application.yml │ ├── db │ └── migration │ │ └── V2022_02_02_1124__initial_structure.sql │ └── repo │ └── org │ └── tomo │ └── ddd_common │ ├── 1.0.0 │ ├── ddd_common-1.0.0.jar │ ├── ddd_common-1.0.0.jar.md5 │ ├── ddd_common-1.0.0.jar.sha1 │ ├── ddd_common-1.0.0.pom │ ├── ddd_common-1.0.0.pom.md5 │ └── ddd_common-1.0.0.pom.sha1 │ ├── maven-metadata.xml │ ├── maven-metadata.xml.md5 │ └── maven-metadata.xml.sha1 └── test ├── java └── com │ └── tomo │ └── mcauthentication │ ├── integration │ ├── BaseIntegrationTest.java │ └── application │ │ ├── AbstractApplicationServiceTest.java │ │ ├── authentication │ │ ├── EmailLoginCommandHandlerTest.java │ │ ├── FacebookLoginCommandHandlerTest.java │ │ ├── GoogleLoginCommandHandlerTest.java │ │ ├── LogoutCommandHandlerTest.java │ │ └── SessionAuthenticationCommandHandlerTest.java │ │ ├── recovery │ │ ├── CreatePasswordRecoveryCodeCommandHandlerTest.java │ │ ├── GetUserRegistrationWithRecoveryCodeQueryHandlerTest.java │ │ └── UpdatePasswordWithRecoveryCodeCommandHandlerTest.java │ │ ├── registration │ │ ├── ChangePasswordCommandHandlerTest.java │ │ ├── ConfirmUserRegistrationCommandHandlerTest.java │ │ └── RegisterNewUserCommandHandlerTest.java │ │ └── users │ │ ├── ChangeUserDetailsCommandHandlerTest.java │ │ └── GetUserQueryHandlerTest.java │ ├── smoke │ └── McAuthenticationApplicationSmokeTest.java │ ├── testdata │ ├── CommandObjectMother.java │ └── StaticFields.java │ ├── unit │ ├── application │ │ └── registration │ │ │ └── UserRegistrationCommandHandlerTest.java │ └── domain │ │ ├── AbstractUnitTest.java │ │ ├── registration │ │ ├── UserRegistrationTest.java │ │ └── rules │ │ │ ├── PasswordRecoveryCodeShouldBeExpiredOrNullTest.java │ │ │ ├── PasswordRecoveryCodeShouldNotExpiredTest.java │ │ │ ├── PasswordsMustMatchTest.java │ │ │ ├── RecoveryCodeMustMatchTest.java │ │ │ ├── UserRegistrationCannotBeConfirmedAfterExpirationTest.java │ │ │ ├── UserRegistrationCannotBeConfirmedMoreThanOnceTest.java │ │ │ ├── UserRegistrationMustBeConfirmedTest.java │ │ │ └── UserRegistrationMustBeUniqueTest.java │ │ ├── session │ │ └── rules │ │ │ └── SessionCannotBeExpiredWhenRefreshTokenIsMissingTest.java │ │ └── user │ │ └── rules │ │ └── UserEmailMustBeUniqueTest.java │ └── weblayer │ ├── BaseWebLayerTest.java │ └── springboot │ └── controller │ ├── AbstractControllerTest.java │ └── RegistrationControllerTest.java └── resources └── application-ci.yml /.env: -------------------------------------------------------------------------------- 1 | COMPOSE_PROJECT_NAME=mc-authentication 2 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | workflow_dispatch: 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | env: 12 | RAILS_ENV: test 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v3 16 | 17 | - uses: satackey/action-docker-layer-caching@v0.0.11 18 | continue-on-error: true 19 | 20 | - name: Start docker containers 21 | run: | 22 | docker-compose -f docker-compose-ci.yml up --build --detach 23 | sleep 10 # wait for database to be ready 24 | 25 | - name: Run unit tests 26 | run: docker-compose -f docker-compose-ci.yml run mc-authentication-service-test ./mvnw test -Punittest -Dspring.profiles.active=ci 27 | 28 | - name: Run integration tests 29 | run: docker-compose -f docker-compose-ci.yml run mc-authentication-service-test ./mvnw test -Pintegrationtest -Dspring.profiles.active=ci 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | .DS_Store 35 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlandeka/authentication-microservice-with-domain-driven-design/a7cfd82824d91d90e1f07a613cdeae1bd59f91e0/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /1-init.sql: -------------------------------------------------------------------------------- 1 | create user mcuser with superuser; 2 | alter user mcuser with password 'mcuser'; 3 | create database mc_authentication with owner mcuser; 4 | create extension "uuid-ossp"; 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM amazoncorretto:11 as base 2 | WORKDIR /app 3 | COPY .mvn/ .mvn 4 | COPY mvnw pom.xml ddd_common-v1.0.0.jar ./ 5 | RUN ./mvnw deploy:deploy-file -Durl=file:./src/main/resources/repo -Dfile=ddd_common-v1.0.0.jar -DgroupId=org.tomo -DartifactId=ddd_common -Dpackaging=jar -Dversion=1.0.0 6 | RUN ./mvnw dependency:resolve 7 | 8 | 9 | FROM base as test 10 | RUN ./mvnw dependency:resolve-plugins -Punittest,integrationtest 11 | COPY src ./src 12 | ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache 13 | CMD tail -f /dev/null 14 | 15 | FROM base as build 16 | COPY src ./src 17 | RUN ./mvnw package 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Tomislav Landeka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ddd_common-v1.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlandeka/authentication-microservice-with-domain-driven-design/a7cfd82824d91d90e1f07a613cdeae1bd59f91e0/ddd_common-v1.0.0.jar -------------------------------------------------------------------------------- /docker-compose-ci.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | 5 | mc-authentication-db-test: 6 | container_name: mc-authentication-db-test 7 | image: postgres:12 8 | restart: always 9 | ports: 10 | - 127.0.0.1:5432:5432 11 | networks: 12 | - mc-network-test 13 | environment: 14 | POSTGRES_PASSWORD: postgres 15 | POSTGRES_USER: postgres 16 | volumes: 17 | - mc-authentication-db-test:/var/lib/postgresql 18 | - ./1-init.sql:/docker-entrypoint-initdb.d/1-init.sql 19 | 20 | mc-authentication-service-test: 21 | container_name: mc-authentication-service-test 22 | depends_on: 23 | - mc-authentication-db-test 24 | build: 25 | context: ./ 26 | dockerfile: Dockerfile 27 | target: test 28 | ports: 29 | - 127.0.0.1:8080:8080 30 | networks: 31 | - mc-network-test 32 | 33 | volumes: 34 | mc-authentication-db-test: 35 | 36 | networks: 37 | mc-network-test: 38 | driver: bridge 39 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | 5 | mc-authentication_db: 6 | container_name: mc-authentication_db 7 | image: postgres:12 8 | restart: always 9 | ports: 10 | - 127.0.0.1:5432:5432 11 | environment: 12 | POSTGRES_PASSWORD: postgres 13 | POSTGRES_USER: postgres 14 | volumes: 15 | - mc-authentication-db:/var/lib/postgresql 16 | - ./1-init.sql:/docker-entrypoint-initdb.d/1-init.sql 17 | 18 | volumes: 19 | mc-authentication-db: 20 | 21 | networks: 22 | mc-network: 23 | driver: bridge 24 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/McAuthenticationApplication.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication; 2 | 3 | import com.tomo.mcauthentication.infrastructure.springboot.configuration.AppProperties; 4 | 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.autoconfigure.domain.EntityScan; 8 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 9 | import org.springframework.context.annotation.ComponentScan; 10 | import org.springframework.context.annotation.EnableAspectJAutoProxy; 11 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 12 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 13 | 14 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 15 | 16 | @EnableWebMvc 17 | @EnableSwagger2 18 | @SpringBootApplication 19 | @EnableConfigurationProperties(AppProperties.class) 20 | @EnableAspectJAutoProxy(proxyTargetClass=true) 21 | @ComponentScan(basePackages = { "com.tomo.*" }) 22 | @EntityScan("com.tomo.*") 23 | public class McAuthenticationApplication { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(McAuthenticationApplication.class, args); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/BaseMapper.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application; 2 | 3 | import org.modelmapper.ModelMapper; 4 | 5 | public class BaseMapper { 6 | protected ModelMapper modelMapper; 7 | 8 | public BaseMapper() {} 9 | 10 | public BaseMapper(ModelMapper modelMapper) { 11 | this.modelMapper = modelMapper; 12 | } 13 | 14 | protected T toDto(E source, Class destinationType) { 15 | return modelMapper.map(source, destinationType); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/McAuthenticationEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application; 2 | 3 | import com.tomo.ddd.domain.DomainEvent; 4 | import com.tomo.ddd.domain.DomainEventPublisher; 5 | import com.tomo.ddd.domain.DomainEventSubscriber; 6 | import com.tomo.ddd.event.EventStore; 7 | 8 | import org.aspectj.lang.annotation.Aspect; 9 | import org.aspectj.lang.annotation.Before; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Aspect 13 | @Component 14 | public class McAuthenticationEventHandler { 15 | 16 | private EventStore eventStore; 17 | 18 | public McAuthenticationEventHandler(EventStore eventStore) { 19 | this.eventStore = eventStore; 20 | } 21 | 22 | @Before(value = "execution(* *(..)) && within(com.tomo.mcauthentication.application..*)") 23 | public void listen() { 24 | DomainEventPublisher 25 | .instance() 26 | .subscribe(new DomainEventSubscriber() { 27 | 28 | public void handleEvent(DomainEvent aDomainEvent) { 29 | store(aDomainEvent); 30 | } 31 | 32 | public Class subscribedToEventType() { 33 | return DomainEvent.class; // all domain events 34 | } 35 | }); 36 | } 37 | 38 | /** 39 | * Stores aDomainEvent to the event store. 40 | * @param aDomainEvent the DomainEvent to store 41 | */ 42 | private void store(DomainEvent aDomainEvent) { 43 | this.eventStore().append(aDomainEvent); 44 | } 45 | 46 | /** 47 | * Answers my EventStore. 48 | * @return EventStore 49 | */ 50 | private EventStore eventStore() { 51 | return this.eventStore; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/BaseLoginCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication; 2 | 3 | import com.tomo.mcauthentication.application.BaseMapper; 4 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 5 | import com.tomo.mcauthentication.domain.session.Session; 6 | import com.tomo.mcauthentication.domain.session.SessionRepository; 7 | import com.tomo.mcauthentication.domain.session.TokenProvider; 8 | 9 | import org.modelmapper.ModelMapper; 10 | 11 | public class BaseLoginCommandHandler extends BaseMapper { 12 | protected SessionRepository sessionRepository; 13 | protected TokenProvider tokenProvider; 14 | 15 | public BaseLoginCommandHandler() { 16 | } 17 | 18 | public BaseLoginCommandHandler(ModelMapper modelMapper, TokenProvider tokenProvider) { 19 | super(modelMapper); 20 | this.tokenProvider = tokenProvider; 21 | } 22 | 23 | public BaseLoginCommandHandler( 24 | ModelMapper modelMapper, 25 | SessionRepository sessionRepository, 26 | TokenProvider tokenProvider) { 27 | super(modelMapper); 28 | this.sessionRepository = sessionRepository; 29 | this.tokenProvider = tokenProvider; 30 | } 31 | 32 | protected SessionDto toDto(Session session) { 33 | return SessionDto.create(session, this.modelMapper); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/EmailLoginCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication; 2 | 3 | import com.tomo.mcauthentication.application.authentication.command.EmailLoginCommand; 4 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 5 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 6 | import com.tomo.mcauthentication.domain.session.Session; 7 | import com.tomo.mcauthentication.domain.session.SessionRepository; 8 | import com.tomo.mcauthentication.domain.session.TokenProvider; 9 | import com.tomo.mcauthentication.domain.registration.EmailAuthenticationService; 10 | import com.tomo.mcauthentication.domain.users.User; 11 | 12 | import org.modelmapper.ModelMapper; 13 | import org.springframework.beans.factory.annotation.Qualifier; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class EmailLoginCommandHandler extends BaseLoginCommandHandler implements CommandHandler { 18 | 19 | EmailAuthenticationService authenticationService; 20 | 21 | public EmailLoginCommandHandler( 22 | EmailAuthenticationService emailAuthenticationService, 23 | @Qualifier("sessionRepositoryJpaAdapter") SessionRepository sessionRepository, 24 | @Qualifier("jwtTokenProvider") TokenProvider tokenProvider, 25 | ModelMapper modelMapper) { 26 | super(modelMapper, sessionRepository, tokenProvider); 27 | this.authenticationService = emailAuthenticationService; 28 | this.tokenProvider = tokenProvider; 29 | } 30 | 31 | @Override 32 | public SessionDto handle(EmailLoginCommand command) { 33 | User user = authenticationService.authenticate(command.getEmail(), command.getPassword()); 34 | Session session = new Session( 35 | sessionRepository.nextIdentity(), 36 | user,tokenProvider, 37 | command.getRememberMe(), 38 | command.getUserAgent(), command.getIpAddress()); 39 | 40 | sessionRepository.save(session); 41 | return toDto(session); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/FacebookLoginCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication; 2 | 3 | import com.tomo.mcauthentication.application.authentication.command.FacebookLoginCommand; 4 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 5 | import com.tomo.mcauthentication.application.users.dto.BaseUserDto; 6 | import com.tomo.mcauthentication.domain.oauth2.OAuth2Service; 7 | import com.tomo.mcauthentication.domain.session.Session; 8 | import com.tomo.mcauthentication.domain.session.SessionRepository; 9 | import com.tomo.mcauthentication.domain.session.TokenProvider; 10 | import com.tomo.mcauthentication.domain.users.User; 11 | 12 | import org.modelmapper.ModelMapper; 13 | import org.springframework.beans.factory.annotation.Qualifier; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class FacebookLoginCommandHandler extends BaseLoginCommandHandler implements CommandHandler { 18 | 19 | OAuth2Service oAuth2Service; 20 | 21 | public FacebookLoginCommandHandler( 22 | @Qualifier("facebookOAuth2Service") OAuth2Service oAuth2Service, 23 | @Qualifier("jwtTokenProvider") TokenProvider tokenProvider, 24 | @Qualifier("sessionRepositoryJpaAdapter") SessionRepository sessionRepository, 25 | ModelMapper modelMapper) { 26 | super(modelMapper, sessionRepository, tokenProvider); 27 | this.oAuth2Service = oAuth2Service; 28 | this.tokenProvider = tokenProvider; 29 | } 30 | 31 | @Override 32 | public BaseUserDto handle(FacebookLoginCommand command) { 33 | User user = oAuth2Service.registerAuthenticate(command.getAccessCode()); 34 | 35 | Session session = new Session( 36 | sessionRepository.nextIdentity(), 37 | user,tokenProvider, 38 | command.getRememberMe(), 39 | command.getUserAgent(), command.getIpAddress()); 40 | sessionRepository.save(session); 41 | 42 | return null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/GoogleLoginCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication; 2 | 3 | import com.tomo.mcauthentication.application.authentication.command.GoogleLoginCommand; 4 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 5 | import com.tomo.mcauthentication.application.users.dto.BaseUserDto; 6 | import com.tomo.mcauthentication.domain.oauth2.OAuth2Service; 7 | import com.tomo.mcauthentication.domain.session.Session; 8 | import com.tomo.mcauthentication.domain.session.SessionRepository; 9 | import com.tomo.mcauthentication.domain.session.TokenProvider; 10 | import com.tomo.mcauthentication.domain.users.User; 11 | 12 | import org.modelmapper.ModelMapper; 13 | import org.springframework.beans.factory.annotation.Qualifier; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class GoogleLoginCommandHandler extends BaseLoginCommandHandler implements CommandHandler { 18 | 19 | OAuth2Service oAuth2Service; 20 | 21 | public GoogleLoginCommandHandler( 22 | @Qualifier("googleOAuth2Service") OAuth2Service oAuth2Service, 23 | @Qualifier("jwtTokenProvider") TokenProvider tokenProvider, 24 | @Qualifier("sessionRepositoryJpaAdapter") SessionRepository sessionRepository, 25 | ModelMapper modelMapper) { 26 | super(modelMapper, sessionRepository, tokenProvider); 27 | this.oAuth2Service = oAuth2Service; 28 | this.tokenProvider = tokenProvider; 29 | } 30 | 31 | @Override 32 | public BaseUserDto handle(GoogleLoginCommand command) { 33 | User user = oAuth2Service.registerAuthenticate(command.getAccessCode()); 34 | Session session = new Session( 35 | sessionRepository.nextIdentity(), 36 | user,tokenProvider, 37 | command.getRememberMe(), 38 | command.getUserAgent(), command.getIpAddress()); 39 | sessionRepository.save(session); 40 | return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/LogoutCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication; 2 | 3 | import com.tomo.mcauthentication.application.authentication.command.LogoutCommand; 4 | import com.tomo.mcauthentication.application.configuration.AbstractVoidyCommandHandler; 5 | import com.tomo.mcauthentication.domain.session.SessionAuthenticationService; 6 | 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class LogoutCommandHandler extends AbstractVoidyCommandHandler { 11 | 12 | SessionAuthenticationService sessionAuthenticationService; 13 | 14 | public LogoutCommandHandler(SessionAuthenticationService sessionAuthenticationService) { 15 | this.sessionAuthenticationService = sessionAuthenticationService; 16 | } 17 | 18 | @Override 19 | protected void abstractHandle(LogoutCommand aCommand) { 20 | sessionAuthenticationService.logout(aCommand.getAuthToken()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/SessionAuthenticationCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication; 2 | 3 | import com.tomo.mcauthentication.application.BaseMapper; 4 | import com.tomo.mcauthentication.application.authentication.command.SessionAuthenticationCommand; 5 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 6 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 7 | import com.tomo.mcauthentication.domain.session.Session; 8 | import com.tomo.mcauthentication.domain.session.SessionAuthenticationService; 9 | 10 | import org.modelmapper.ModelMapper; 11 | import org.springframework.stereotype.Service; 12 | 13 | @Service 14 | public class SessionAuthenticationCommandHandler extends BaseMapper implements CommandHandler { 15 | 16 | SessionAuthenticationService sessionAuthenticationService; 17 | 18 | public SessionAuthenticationCommandHandler( 19 | SessionAuthenticationService sessionAuthenticationService, 20 | ModelMapper modelMapper) { 21 | super(modelMapper); 22 | this.sessionAuthenticationService = sessionAuthenticationService; 23 | } 24 | 25 | @Override 26 | public SessionDto handle(SessionAuthenticationCommand command) { 27 | Session session = sessionAuthenticationService.authenticate(command.getAuthToken()); 28 | return SessionDto.create(session, this.modelMapper); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/command/BaseLoginCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseCommand; 4 | 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | @Getter 9 | @Setter 10 | public class BaseLoginCommand extends BaseCommand { 11 | private Boolean rememberMe; 12 | private String userAgent; 13 | private String ipAddress; 14 | 15 | public BaseLoginCommand() { 16 | super(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/command/EmailLoginCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication.command; 2 | 3 | import javax.validation.constraints.Email; 4 | import javax.validation.constraints.NotBlank; 5 | 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | 9 | @Setter 10 | @Getter 11 | public class EmailLoginCommand extends BaseLoginCommand { 12 | 13 | @NotBlank 14 | @Email 15 | private String email; 16 | @NotBlank 17 | private String password; 18 | private Boolean rememberMe; 19 | private String userAgent; 20 | private String ipAddress; 21 | 22 | public EmailLoginCommand() { 23 | super(); 24 | } 25 | 26 | public EmailLoginCommand(String email, String password) { 27 | super(); 28 | this.email = email; 29 | this.password = password; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/command/FacebookLoginCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication.command; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | @Setter 8 | @Getter 9 | @NoArgsConstructor 10 | public class FacebookLoginCommand extends BaseLoginCommand { 11 | private String accessCode; 12 | 13 | public FacebookLoginCommand(String accessCode) { 14 | this.accessCode = accessCode; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/command/GoogleLoginCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication.command; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | @Setter 8 | @Getter 9 | @NoArgsConstructor 10 | public class GoogleLoginCommand extends BaseLoginCommand { 11 | private String accessCode; 12 | 13 | public GoogleLoginCommand(String accessCode) { 14 | this.accessCode = accessCode; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/command/LogoutCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.security.AbstractAuthenticateCommand; 4 | 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Setter 10 | @Getter 11 | @NoArgsConstructor 12 | public class LogoutCommand extends AbstractAuthenticateCommand { 13 | 14 | public LogoutCommand(String authToken) { 15 | super(authToken); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/command/SessionAuthenticationCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.security.AbstractAuthenticateCommand; 4 | 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | public class SessionAuthenticationCommand extends AbstractAuthenticateCommand { 13 | 14 | public SessionAuthenticationCommand(String authToken) { 15 | super(authToken); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/dto/RecoveryPasswordDto.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication.dto; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Response; 4 | 5 | import lombok.Getter; 6 | 7 | @Getter 8 | public class RecoveryPasswordDto implements Response { 9 | 10 | String recoveryCode; 11 | 12 | public RecoveryPasswordDto(String recoveryCode) { 13 | this.recoveryCode = recoveryCode; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/authentication/dto/SessionDto.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.authentication.dto; 2 | 3 | import com.tomo.mcauthentication.application.users.dto.BaseUserDto; 4 | import com.tomo.mcauthentication.domain.session.Session; 5 | import com.tomo.mcauthentication.domain.session.SessionId; 6 | import com.tomo.mcauthentication.domain.users.UserId; 7 | 8 | import org.modelmapper.ModelMapper; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | import lombok.Getter; 13 | import lombok.NoArgsConstructor; 14 | import lombok.Setter; 15 | 16 | @Getter 17 | @Setter 18 | @NoArgsConstructor 19 | public class SessionDto extends BaseUserDto { 20 | private String sessionId; 21 | private String accessToken; 22 | private LocalDateTime expirationDate; 23 | int expirationDateMilis; 24 | private String tokenType; 25 | private String refreshToken; 26 | private String userAgent; 27 | private String ipAddress; 28 | private LocalDateTime lastActivity; 29 | private String userId; 30 | 31 | public static SessionDto create(Session session, ModelMapper mapper) { 32 | SessionDto dto = mapper.map(session, SessionDto.class); 33 | dto.setTokenType(session.getTokenType()); 34 | dto.setUserId(session.getUserId()); 35 | return dto; 36 | } 37 | 38 | public void setSessionId(SessionId sessionId) { 39 | this.sessionId = sessionId.toString(); 40 | } 41 | 42 | public void setTokenType(Session.TokenType tokenType) { 43 | this.tokenType = tokenType.toString(); 44 | } 45 | 46 | public void setUserId(UserId userId) { 47 | this.userId = userId.id().toString(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/configuration/AbstractVoidyCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.configuration; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Command; 4 | import com.tomo.mcauthentication.application.contracts.Voidy; 5 | 6 | import javax.transaction.Transactional; 7 | 8 | public abstract class AbstractVoidyCommandHandler implements CommandHandler { 9 | 10 | @Override 11 | @Transactional 12 | public Voidy handle(T aCommand) { 13 | abstractHandle(aCommand); 14 | return new Voidy(); 15 | } 16 | 17 | abstract protected void abstractHandle(T aCommand); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/configuration/CommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.configuration; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Command; 4 | import com.tomo.mcauthentication.application.contracts.Response; 5 | 6 | public interface CommandHandler extends RequestHandler { 7 | R handle(T aCommand); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/configuration/QueryHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.configuration; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Query; 4 | import com.tomo.mcauthentication.application.contracts.Response; 5 | 6 | public interface QueryHandler extends RequestHandler { 7 | R handle(T query); 8 | } 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/configuration/RequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.configuration; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Request; 4 | import com.tomo.mcauthentication.application.contracts.Response; 5 | 6 | public interface RequestHandler { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/BaseCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | public class BaseCommand extends BaseRequest implements Command { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/BaseQuery.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | public class BaseQuery extends BaseRequest implements Query {} 4 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/BaseRequest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | import java.util.UUID; 4 | 5 | public class BaseRequest implements Request { 6 | 7 | private UUID id; 8 | 9 | public BaseRequest() { 10 | setId(UUID.randomUUID()); 11 | } 12 | 13 | public BaseRequest(UUID anId) { 14 | this.id = anId; 15 | } 16 | 17 | @Override 18 | public UUID id() { 19 | return this.id; 20 | } 21 | 22 | protected void setId(UUID anId) { 23 | this.id = anId; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/Command.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | public interface Command extends Request { 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/Identifiable.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | import java.util.UUID; 4 | 5 | public interface Identifiable { 6 | 7 | UUID id(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/McAuthenticationModule.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | @Component 6 | public interface McAuthenticationModule { 7 | Response executeCommand(Command command); 8 | 9 | Response executeQuery(Query query); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/Query.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | public interface Query extends Request { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/Request.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | public interface Request extends Identifiable { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/Response.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | public interface Response { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/Voidy.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts; 2 | 3 | public class Voidy implements Response { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/security/AbstractAuthenticateCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts.security; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Command; 4 | 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | public abstract class AbstractAuthenticateCommand extends AbstractAuthenticateRequest implements Command { 13 | 14 | public AbstractAuthenticateCommand(String authToken) { 15 | super(authToken); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/security/AbstractAuthenticateQuery.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts.security; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseRequest; 4 | import com.tomo.mcauthentication.application.contracts.Command; 5 | import com.tomo.mcauthentication.application.contracts.Query; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public abstract class AbstractAuthenticateQuery extends AbstractAuthenticateRequest implements Query { 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/security/AbstractAuthenticateRequest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts.security; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseRequest; 4 | import com.tomo.mcauthentication.application.contracts.Command; 5 | import com.tomo.mcauthentication.application.contracts.Request; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public abstract class AbstractAuthenticateRequest extends BaseRequest implements Authenticate, Request { 15 | 16 | String authToken; 17 | 18 | public AbstractAuthenticateRequest(String authToken) { 19 | this.authToken = authToken; 20 | } 21 | 22 | @Override 23 | public String authToken() { 24 | return this.authToken; 25 | } 26 | 27 | @Override 28 | public void setAuthToken(String authToken) { 29 | this.authToken = authToken; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/security/AbstractAuthorizeCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts.security; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Command; 4 | 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | public abstract class AbstractAuthorizeCommand extends AbstractAuthorizeRequest implements Command { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/security/AbstractAuthorizeQuery.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts.security; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Command; 4 | import com.tomo.mcauthentication.application.contracts.Query; 5 | 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public abstract class AbstractAuthorizeQuery extends AbstractAuthorizeRequest implements Query { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/security/AbstractAuthorizeRequest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts.security; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Command; 4 | import com.tomo.mcauthentication.application.contracts.Request; 5 | 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public abstract class AbstractAuthorizeRequest extends AbstractAuthenticateRequest implements Request, Authorize { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/security/Authenticate.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts.security; 2 | 3 | public interface Authenticate { 4 | 5 | String authToken(); 6 | 7 | void setAuthToken(String authToken); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/contracts/security/Authorize.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.contracts.security; 2 | 3 | import java.util.List; 4 | 5 | public interface Authorize extends Authenticate { 6 | 7 | default List getAuthorities() { 8 | return List.of("USER"); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/recovery/CreatePasswordRecoveryCodeCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.recovery; 2 | 3 | import com.tomo.mcauthentication.application.recovery.command.CreatePasswordRecoveryCodeCommand; 4 | import com.tomo.mcauthentication.application.authentication.dto.RecoveryPasswordDto; 5 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 6 | import com.tomo.mcauthentication.domain.registration.EmailAuthenticationService; 7 | 8 | import org.springframework.stereotype.Service; 9 | 10 | @Service 11 | public class CreatePasswordRecoveryCodeCommandHandler implements CommandHandler { 12 | 13 | EmailAuthenticationService emailAuthenticationService; 14 | 15 | public CreatePasswordRecoveryCodeCommandHandler(EmailAuthenticationService emailAuthenticationService) { 16 | this.emailAuthenticationService = emailAuthenticationService; 17 | } 18 | 19 | @Override 20 | public RecoveryPasswordDto handle(CreatePasswordRecoveryCodeCommand aCommand) { 21 | return new RecoveryPasswordDto( 22 | emailAuthenticationService 23 | .createPasswordRecoveryCode(aCommand.getEmail()) 24 | ); 25 | 26 | //todo send recovery code 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/recovery/GetUserRegistrationWithRecoveryCodeQueryHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.recovery; 2 | 3 | import com.tomo.mcauthentication.application.BaseMapper; 4 | import com.tomo.mcauthentication.application.configuration.QueryHandler; 5 | import com.tomo.mcauthentication.application.registration.dto.UserRegistrationDto; 6 | import com.tomo.mcauthentication.application.recovery.dto.GetUserRegistrationWithRecoveryCodeQuery; 7 | import com.tomo.mcauthentication.domain.EncryptionService; 8 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 9 | import com.tomo.mcauthentication.domain.registration.UserRegistrationRepository; 10 | 11 | import org.modelmapper.ModelMapper; 12 | import org.springframework.stereotype.Component; 13 | 14 | @Component 15 | public class GetUserRegistrationWithRecoveryCodeQueryHandler extends BaseMapper implements QueryHandler { 16 | 17 | private UserRegistrationRepository userRegistrationRepository; 18 | private EncryptionService encryptionService; 19 | 20 | public GetUserRegistrationWithRecoveryCodeQueryHandler( 21 | UserRegistrationRepository aUserRegistrationRepository, 22 | EncryptionService anEncryptionService, 23 | ModelMapper modelMapper) { 24 | super(modelMapper); 25 | this.userRegistrationRepository = aUserRegistrationRepository; 26 | this.encryptionService = anEncryptionService; 27 | } 28 | 29 | @Override 30 | public UserRegistrationDto handle(GetUserRegistrationWithRecoveryCodeQuery query) { 31 | UserRegistration userRegistration = userRegistrationRepository 32 | .findByRecoveryCode(encryptionService.encryptedValue(query.getRecoveryCode())); 33 | 34 | if (userRegistration == null) { 35 | throw new IllegalStateException(String.format("User with recovery code %s doesn't exists.", query.getRecoveryCode())); 36 | } 37 | 38 | UserRegistrationDto dto = toDto( 39 | userRegistration, 40 | UserRegistrationDto.class 41 | ); 42 | return dto; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/recovery/PasswordRecoveryCodeCreatedEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.recovery; 2 | 3 | import com.tomo.mcauthentication.application.contracts.McAuthenticationModule; 4 | import com.tomo.mcauthentication.application.recovery.command.SendPasswordRecoveryEmailCommand; 5 | import com.tomo.ddd.domain.DomainEventPublisher; 6 | import com.tomo.ddd.domain.DomainEventSubscriber; 7 | import com.tomo.mcauthentication.domain.registration.events.PasswordRecoveryCodeCreated; 8 | 9 | import org.aspectj.lang.annotation.Aspect; 10 | import org.aspectj.lang.annotation.Before; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Aspect 14 | @Component 15 | public class PasswordRecoveryCodeCreatedEventHandler { 16 | 17 | private McAuthenticationModule module; 18 | 19 | /** 20 | * In order to not mix business logic with plugins like a GUI.. 21 | * baseUrl + URI + queryString eg. localhost/reset-passwrod/?recoveryCode= 22 | */ 23 | private String recoveryLink; 24 | 25 | public PasswordRecoveryCodeCreatedEventHandler(McAuthenticationModule authenticationModule, String recoveryLink) { 26 | this.module = authenticationModule; 27 | this.recoveryLink = recoveryLink; 28 | } 29 | 30 | @Before("execution(" + 31 | "public * com.tomo.mcauthentication.application.configuration.CommandHandler.*(..)) && " + 32 | "target(com.tomo.mcauthentication.application.recovery.CreatePasswordRecoveryCodeCommandHandler))") 33 | public void listen() { 34 | DomainEventPublisher 35 | .instance() 36 | .subscribe(new DomainEventSubscriber() { 37 | 38 | public void handleEvent(PasswordRecoveryCodeCreated aDomainEvent) { 39 | module.executeCommand(new SendPasswordRecoveryEmailCommand( 40 | aDomainEvent.getEmail(), 41 | aDomainEvent.getRecoveryCode(), 42 | recoveryLink, 43 | aDomainEvent.getRecoveryCodeExpirationDate())); 44 | } 45 | 46 | public Class subscribedToEventType() { 47 | return PasswordRecoveryCodeCreated.class; 48 | } 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/recovery/SendPasswordRecoveryEmailCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.recovery; 2 | 3 | import com.tomo.mcauthentication.application.configuration.AbstractVoidyCommandHandler; 4 | import com.tomo.mcauthentication.application.recovery.command.SendPasswordRecoveryEmailCommand; 5 | import com.tomo.ddd.email.EmailSender; 6 | import com.tomo.ddd.port.adapter.message.email.EmailMessage; 7 | 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class SendPasswordRecoveryEmailCommandHandler extends AbstractVoidyCommandHandler { 12 | 13 | EmailSender emailMessageSender; 14 | 15 | public SendPasswordRecoveryEmailCommandHandler(EmailSender emailMessageSender) { 16 | this.emailMessageSender = emailMessageSender; 17 | } 18 | 19 | @Override 20 | protected void abstractHandle(SendPasswordRecoveryEmailCommand aCommand) { 21 | //todo maybe validate if exist 22 | this.emailMessageSender.send(new EmailMessage( 23 | aCommand.getEmail(), "" 24 | , " Recovery code", 25 | "To reset your password, visit the following link: " + aCommand.getRecoveryLink() + aCommand.getRecoveryCode())); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/recovery/UpdatePasswordWithRecoveryCodeCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.recovery; 2 | 3 | import com.tomo.mcauthentication.application.recovery.command.UpdatePasswordWithRecoveryCodeCommand; 4 | import com.tomo.mcauthentication.application.configuration.AbstractVoidyCommandHandler; 5 | import com.tomo.mcauthentication.domain.registration.EmailAuthenticationService; 6 | 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class UpdatePasswordWithRecoveryCodeCommandHandler extends AbstractVoidyCommandHandler { 11 | 12 | EmailAuthenticationService emailAuthenticationService; 13 | 14 | public UpdatePasswordWithRecoveryCodeCommandHandler(EmailAuthenticationService emailAuthenticationService) { 15 | this.emailAuthenticationService = emailAuthenticationService; 16 | } 17 | 18 | @Override 19 | protected void abstractHandle(UpdatePasswordWithRecoveryCodeCommand aCommand) { 20 | emailAuthenticationService.recoverPasswordWithRecoveryCode( 21 | aCommand.getRecoveryCode(), 22 | aCommand.getNewPassword(), 23 | aCommand.getNewPasswordRepeated()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/recovery/command/CreatePasswordRecoveryCodeCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.recovery.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseCommand; 4 | 5 | import javax.validation.constraints.NotNull; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class CreatePasswordRecoveryCodeCommand extends BaseCommand { 15 | 16 | @NotNull 17 | private String email; 18 | 19 | public CreatePasswordRecoveryCodeCommand(String email) { 20 | this.email = email; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/recovery/command/SendPasswordRecoveryEmailCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.recovery.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseCommand; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class SendPasswordRecoveryEmailCommand extends BaseCommand { 15 | 16 | String email; 17 | String recoveryCode; 18 | String recoveryLink; 19 | LocalDateTime recoveryCodeExpirationDate; 20 | 21 | public SendPasswordRecoveryEmailCommand(String email, String recoveryCode, String recoveryLink, LocalDateTime recoveryCodeExpirationDate) { 22 | this.email = email; 23 | this.recoveryCode = recoveryCode; 24 | this.recoveryLink = recoveryLink; 25 | this.recoveryCodeExpirationDate = recoveryCodeExpirationDate; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/recovery/command/UpdatePasswordWithRecoveryCodeCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.recovery.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseCommand; 4 | 5 | import javax.validation.constraints.NotNull; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class UpdatePasswordWithRecoveryCodeCommand extends BaseCommand { 15 | 16 | @NotNull 17 | private String newPassword; 18 | 19 | @NotNull 20 | private String newPasswordRepeated; 21 | 22 | @NotNull 23 | private String recoveryCode; 24 | 25 | public UpdatePasswordWithRecoveryCodeCommand(String newPassword, String newPasswordRepeated, String recoveryCode) { 26 | this.newPassword = newPassword; 27 | this.newPasswordRepeated = newPasswordRepeated; 28 | this.recoveryCode = recoveryCode; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/recovery/dto/GetUserRegistrationWithRecoveryCodeQuery.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.recovery.dto; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseQuery; 4 | 5 | import javax.validation.constraints.NotNull; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class GetUserRegistrationWithRecoveryCodeQuery extends BaseQuery { 15 | 16 | @NotNull 17 | String recoveryCode; 18 | 19 | public GetUserRegistrationWithRecoveryCodeQuery(String recoveryCode) { 20 | this.recoveryCode = recoveryCode; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/ChangePasswordCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration; 2 | 3 | import com.tomo.mcauthentication.application.configuration.AbstractVoidyCommandHandler; 4 | import com.tomo.mcauthentication.application.registration.command.ChangePasswordCommand; 5 | import com.tomo.mcauthentication.domain.registration.EmailAuthenticationService; 6 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 7 | import com.tomo.mcauthentication.domain.registration.UserRegistrationRepository; 8 | import com.tomo.mcauthentication.domain.session.Session; 9 | import com.tomo.mcauthentication.domain.session.SessionAuthenticationService; 10 | 11 | import org.springframework.stereotype.Service; 12 | 13 | @Service 14 | public class ChangePasswordCommandHandler extends AbstractVoidyCommandHandler { 15 | 16 | EmailAuthenticationService emailAuthenticationService; 17 | SessionAuthenticationService sessionAuthenticationService; 18 | UserRegistrationRepository userRegistrationRepository; 19 | 20 | public ChangePasswordCommandHandler( 21 | EmailAuthenticationService emailAuthenticationService, 22 | SessionAuthenticationService aSessionAuthenticationService, 23 | UserRegistrationRepository anUserRegistrationRepository) { 24 | this.emailAuthenticationService = emailAuthenticationService; 25 | this.sessionAuthenticationService = aSessionAuthenticationService; 26 | this.userRegistrationRepository = anUserRegistrationRepository; 27 | } 28 | 29 | @Override 30 | protected void abstractHandle(ChangePasswordCommand aCommand) { 31 | Session session = sessionAuthenticationService.authenticate(aCommand.getAccessToken()); 32 | 33 | UserRegistration userRegistration = userRegistrationRepository.findByUserId(session.getUserId()); 34 | 35 | if (userRegistration == null) { 36 | throw new IllegalStateException(String.format("User with id %s doesn't exist.", session.getUserId().id())); 37 | } 38 | 39 | userRegistration.changePassword(aCommand.getOldPassword(), aCommand.getNewPassword(), aCommand.getNewPasswordRepeated()); 40 | userRegistrationRepository.save(userRegistration); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/ConfirmUserRegistrationCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration; 2 | 3 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 4 | import com.tomo.mcauthentication.application.registration.command.ConfirmUserRegistrationCommand; 5 | import com.tomo.mcauthentication.application.users.dto.BaseUserDto; 6 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 7 | import com.tomo.mcauthentication.domain.registration.UserRegistrationRepository; 8 | import com.tomo.mcauthentication.domain.users.User; 9 | import com.tomo.mcauthentication.domain.users.UserRepository; 10 | 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public class ConfirmUserRegistrationCommandHandler implements CommandHandler { 15 | 16 | UserRegistrationRepository userRegistrationRepository; 17 | UserRepository userRepository; 18 | 19 | public ConfirmUserRegistrationCommandHandler( 20 | UserRegistrationRepository userRegistrationRepository, 21 | UserRepository userRepository) { 22 | this.userRegistrationRepository = userRegistrationRepository; 23 | this.userRepository = userRepository; 24 | } 25 | 26 | @Override 27 | public BaseUserDto handle(ConfirmUserRegistrationCommand command) { 28 | UserRegistration userRegistration = userRegistrationRepository.findByConfirmationCode(command.getConfirmationLink()); 29 | 30 | if (userRegistration == null) { 31 | throw new IllegalStateException( 32 | String.format("UserRegistration with confirmation link %s cannot be found.", command.getConfirmationLink()) 33 | ); 34 | } 35 | 36 | User user = userRegistration.createUser(userRepository); 37 | userRegistration.setUserId(user.getUserId()); 38 | 39 | userRepository.save(user); 40 | userRegistrationRepository.save(userRegistration); 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/GetUserRegistrationQueryHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration; 2 | 3 | import com.tomo.mcauthentication.application.configuration.QueryHandler; 4 | import com.tomo.mcauthentication.application.registration.dto.UserRegistrationDto; 5 | import com.tomo.mcauthentication.application.registration.query.GetUserRegistrationQuery; 6 | 7 | public class GetUserRegistrationQueryHandler implements QueryHandler { 8 | 9 | @Override public UserRegistrationDto handle(GetUserRegistrationQuery request) { 10 | return null; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/NewUserRegisteredEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration; 2 | 3 | import com.tomo.mcauthentication.application.contracts.McAuthenticationModule; 4 | import com.tomo.mcauthentication.application.registration.command.SendRegistrationConfirmationEmailCommand; 5 | import com.tomo.ddd.domain.DomainEventPublisher; 6 | import com.tomo.ddd.domain.DomainEventSubscriber; 7 | import com.tomo.mcauthentication.domain.registration.events.UserRegistrationRequested; 8 | 9 | import org.aspectj.lang.annotation.Aspect; 10 | import org.aspectj.lang.annotation.Before; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Aspect 14 | @Component 15 | public class NewUserRegisteredEventHandler { 16 | 17 | private McAuthenticationModule authenticationModule; 18 | 19 | /** 20 | * In order to not mix business logic with plugins like a GUI.. 21 | * baseUrl + URI + queryString eg. localhost/register/confirm/?confirmationCode= 22 | */ 23 | private String confirmationLink; 24 | 25 | public NewUserRegisteredEventHandler(McAuthenticationModule authenticationModule, String confirmationLink) { 26 | this.authenticationModule = authenticationModule; 27 | this.confirmationLink = confirmationLink; 28 | } 29 | 30 | @Before(value = "execution(public * com.tomo.mcauthentication.application.configuration.AbstractVoidyCommandHandler.*(..)) && target(com.tomo.mcauthentication.application.registration.RegisterNewUserCommandHandler))") 31 | public void listen() { 32 | DomainEventPublisher 33 | .instance() 34 | .subscribe(new DomainEventSubscriber() { 35 | 36 | public void handleEvent(UserRegistrationRequested aDomainEvent) { 37 | authenticationModule.executeCommand(new SendRegistrationConfirmationEmailCommand( 38 | aDomainEvent.getEmail(), 39 | confirmationLink, 40 | aDomainEvent.getConfirmationCode())); 41 | } 42 | 43 | public Class subscribedToEventType() { 44 | return UserRegistrationRequested.class; // all domain events 45 | } 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/RegisterNewUserCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration; 2 | 3 | import com.tomo.mcauthentication.application.configuration.AbstractVoidyCommandHandler; 4 | import com.tomo.mcauthentication.application.registration.command.RegisterNewUserCommand; 5 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 6 | import com.tomo.mcauthentication.domain.registration.UserRegistrationRepository; 7 | import com.tomo.mcauthentication.domain.users.UserRepository; 8 | 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public class RegisterNewUserCommandHandler extends AbstractVoidyCommandHandler { 13 | 14 | UserRegistrationRepository userRegistrationRepository; 15 | UserRepository userRepository; 16 | 17 | public RegisterNewUserCommandHandler( 18 | UserRegistrationRepository userRegistrationRepository, 19 | UserRepository userRepository) { 20 | this.userRegistrationRepository = userRegistrationRepository; 21 | this.userRepository = userRepository; 22 | } 23 | 24 | @Override 25 | protected void abstractHandle(RegisterNewUserCommand aCommand) { 26 | UserRegistration userRegistration = UserRegistration.registerNewUser( 27 | aCommand.getPassword(), 28 | aCommand.getEmail(), 29 | aCommand.getFirstName(), 30 | aCommand.getLastName() 31 | ); 32 | 33 | userRegistrationRepository.save(userRegistration); 34 | //todo send email 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/SendRegistrationConfirmationEmailCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration; 2 | 3 | import com.tomo.mcauthentication.application.configuration.AbstractVoidyCommandHandler; 4 | import com.tomo.mcauthentication.application.registration.command.SendRegistrationConfirmationEmailCommand; 5 | import com.tomo.ddd.email.EmailSender; 6 | import com.tomo.ddd.port.adapter.message.email.EmailMessage; 7 | 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class SendRegistrationConfirmationEmailCommandHandler extends AbstractVoidyCommandHandler { 12 | 13 | EmailSender emailMessageSender; 14 | 15 | public SendRegistrationConfirmationEmailCommandHandler(EmailSender emailMessageSender) { 16 | this.emailMessageSender = emailMessageSender; 17 | } 18 | 19 | @Override 20 | protected void abstractHandle(SendRegistrationConfirmationEmailCommand aCommand) { 21 | //todo maybe validate if exist 22 | this.emailMessageSender.send(new EmailMessage( 23 | aCommand.getEmail(), "" 24 | , "Confirm registration", 25 | "Click on this confirmation link " + aCommand.getConfirmLink() + aCommand.getConfirmationCode())); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/command/ChangePasswordCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseCommand; 4 | 5 | import javax.validation.constraints.NotNull; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class ChangePasswordCommand extends BaseCommand { 15 | 16 | String accessToken; 17 | 18 | @NotNull 19 | private String oldPassword; 20 | 21 | @NotNull 22 | private String newPassword; 23 | 24 | @NotNull 25 | private String newPasswordRepeated; 26 | 27 | public ChangePasswordCommand(String accessToken, String oldPassword, String newPassword, String newPasswordRepeated) { 28 | this.accessToken = accessToken; 29 | this.oldPassword = oldPassword; 30 | this.newPassword = newPassword; 31 | this.newPasswordRepeated = newPasswordRepeated; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/command/ConfirmUserRegistrationCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseCommand; 4 | 5 | import java.util.UUID; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Setter 12 | @Getter 13 | @NoArgsConstructor 14 | public class ConfirmUserRegistrationCommand extends BaseCommand { 15 | 16 | private String confirmationLink; 17 | 18 | public ConfirmUserRegistrationCommand(String confirmLink) { 19 | this.confirmationLink = confirmLink; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/command/RegisterNewUserCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseCommand; 4 | 5 | import javax.validation.constraints.NotNull; 6 | import java.util.UUID; 7 | 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | import lombok.Setter; 11 | 12 | @Getter 13 | @Setter 14 | @NoArgsConstructor 15 | public class RegisterNewUserCommand extends BaseCommand { 16 | 17 | @NotNull 18 | String firstName; 19 | 20 | @NotNull 21 | String lastName; 22 | 23 | @NotNull 24 | String email; 25 | 26 | @NotNull 27 | String password; 28 | 29 | public RegisterNewUserCommand(String firstName, String lastName, String email, String password) { 30 | this.firstName = firstName; 31 | this.lastName = lastName; 32 | this.email = email; 33 | this.password = password; 34 | } 35 | 36 | public String getPassword() { 37 | return password; 38 | } 39 | 40 | public void setPassword(String password) { 41 | this.password = password; 42 | } 43 | 44 | public String getEmail() { 45 | return email; 46 | } 47 | 48 | public void setEmail(String email) { 49 | this.email = email; 50 | } 51 | 52 | public String getFirstName() { 53 | return firstName; 54 | } 55 | 56 | public void setFirstName(String firstName) { 57 | this.firstName = firstName; 58 | } 59 | 60 | public String getLastName() { 61 | return lastName; 62 | } 63 | 64 | public void setLastName(String lastName) { 65 | this.lastName = lastName; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/command/SendRegistrationConfirmationEmailCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseCommand; 4 | 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | public class SendRegistrationConfirmationEmailCommand extends BaseCommand { 13 | String email; 14 | String confirmLink; 15 | String confirmationCode; 16 | 17 | public SendRegistrationConfirmationEmailCommand(String email, String confirmLink, String confirmationCode) { 18 | this.email = email; 19 | this.confirmLink = confirmLink; 20 | this.confirmationCode = confirmationCode; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/dto/UserRegistrationDto.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration.dto; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Response; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistrationId; 5 | import com.tomo.mcauthentication.domain.registration.UserRegistrationStatus; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | import lombok.Getter; 10 | import lombok.NoArgsConstructor; 11 | import lombok.Setter; 12 | 13 | @Getter 14 | @Setter 15 | @NoArgsConstructor 16 | public class UserRegistrationDto implements Response { 17 | 18 | private String email; 19 | private String firstName; 20 | private String lastName; 21 | private LocalDateTime registerDate; 22 | private UserRegistrationStatus status; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/registration/query/GetUserRegistrationQuery.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.registration.query; 2 | 3 | import com.tomo.mcauthentication.application.contracts.BaseQuery; 4 | 5 | import java.util.UUID; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class GetUserRegistrationQuery extends BaseQuery { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/users/ChangeUserDetailsCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.users; 2 | 3 | import com.tomo.mcauthentication.application.configuration.AbstractVoidyCommandHandler; 4 | import com.tomo.mcauthentication.application.users.command.ChangeUserDetailsCommand; 5 | import com.tomo.mcauthentication.domain.registration.EmailAuthenticationService; 6 | import com.tomo.mcauthentication.domain.session.TokenProvider; 7 | import com.tomo.mcauthentication.domain.users.User; 8 | import com.tomo.mcauthentication.domain.users.UserId; 9 | import com.tomo.mcauthentication.domain.users.UserRepository; 10 | 11 | import org.springframework.stereotype.Service; 12 | 13 | import lombok.AllArgsConstructor; 14 | 15 | @Service 16 | @AllArgsConstructor 17 | public class ChangeUserDetailsCommandHandler extends AbstractVoidyCommandHandler { 18 | 19 | EmailAuthenticationService emailAuthenticationService; 20 | TokenProvider tokenProvider; 21 | UserRepository userRepository; 22 | 23 | @Override 24 | public void abstractHandle(ChangeUserDetailsCommand aCommand) { 25 | UserId userId = tokenProvider.getUserIdFromToken(aCommand.getAuthToken()); 26 | 27 | if (!aCommand.getUserId().equals(userId.id())) { 28 | throw new IllegalArgumentException(String.format("Forbidden access. User with ID %s cannot change user details for user with ID: %s", userId.id(), aCommand.getUserId())); 29 | } 30 | 31 | User user = userRepository.findById(new UserId(aCommand.getUserId())); 32 | user.updateDetails(aCommand.getFirstName(), aCommand.getLastName()); 33 | 34 | userRepository.save(user); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/users/GetUserQueryHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.users; 2 | 3 | import com.tomo.mcauthentication.application.BaseMapper; 4 | import com.tomo.mcauthentication.application.configuration.QueryHandler; 5 | import com.tomo.mcauthentication.application.users.dto.BaseUserDto; 6 | import com.tomo.mcauthentication.application.users.query.GetUserQuery; 7 | import com.tomo.mcauthentication.domain.users.User; 8 | import com.tomo.mcauthentication.domain.users.UserRepository; 9 | 10 | import org.modelmapper.ModelMapper; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public class GetUserQueryHandler extends BaseMapper implements QueryHandler { 15 | 16 | private UserRepository userRepository; 17 | 18 | public GetUserQueryHandler( 19 | UserRepository userRepository, 20 | ModelMapper modelMapper) { 21 | super(modelMapper); 22 | this.userRepository = userRepository; 23 | } 24 | 25 | @Override 26 | public BaseUserDto handle(GetUserQuery query) { 27 | User user = userRepository.findById(query.getUserId()); 28 | 29 | if (user == null) { 30 | throw new IllegalStateException(String.format("User with id %s doesn't exists.", query.getUserId().toString())); 31 | } 32 | 33 | return toDto(user); 34 | } 35 | 36 | private BaseUserDto toDto(User user) { 37 | return modelMapper.map(user, BaseUserDto.class); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/users/command/ChangeUserDetailsCommand.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.users.command; 2 | 3 | import com.tomo.mcauthentication.application.contracts.security.AbstractAuthorizeCommand; 4 | 5 | import java.util.List; 6 | import java.util.UUID; 7 | 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | import lombok.Setter; 11 | 12 | @Getter 13 | @Setter 14 | @NoArgsConstructor 15 | public class ChangeUserDetailsCommand extends AbstractAuthorizeCommand { 16 | 17 | private UUID userId; 18 | private String firstName; 19 | private String lastName; 20 | 21 | public ChangeUserDetailsCommand(UUID userId, String firstName, String lastName) { 22 | this.userId = userId; 23 | this.firstName = firstName; 24 | this.lastName = lastName; 25 | } 26 | 27 | @Override 28 | public List getAuthorities() { 29 | List authorities = super.getAuthorities(); 30 | authorities.add("ADMIN"); 31 | return authorities; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/users/dto/BaseUserDto.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.users.dto; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Response; 4 | import com.tomo.mcauthentication.domain.users.UserId; 5 | 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public class BaseUserDto implements Response { 14 | private String userId; 15 | String firstName; 16 | String lastName; 17 | 18 | public void setUserId(UserId userId) { 19 | this.userId = userId.id().toString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/application/users/query/GetUserQuery.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.application.users.query; 2 | 3 | import com.tomo.mcauthentication.application.contracts.security.AbstractAuthenticateQuery; 4 | import com.tomo.mcauthentication.domain.users.UserId; 5 | 6 | import javax.validation.constraints.NotNull; 7 | import java.util.UUID; 8 | 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | 12 | @Getter 13 | @Setter 14 | public class GetUserQuery extends AbstractAuthenticateQuery { 15 | 16 | @NotNull 17 | String userId; 18 | 19 | public GetUserQuery(String userId) { 20 | this.userId = userId; 21 | } 22 | 23 | public UserId getUserId() { 24 | return new UserId(UUID.fromString(this.userId)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/DomainRegistry.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain; 2 | 3 | import com.tomo.mcauthentication.domain.registration.PasswordService; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistrationRepository; 5 | import com.tomo.mcauthentication.domain.registration.rules.UserRegistrationMustBeUnique; 6 | import com.tomo.mcauthentication.domain.session.TokenProvider; 7 | import com.tomo.mcauthentication.domain.users.UserRepository; 8 | import com.tomo.mcauthentication.domain.users.rules.UserEmailMustBeUnique; 9 | 10 | import org.modelmapper.ModelMapper; 11 | import org.springframework.beans.BeansException; 12 | import org.springframework.context.ApplicationContext; 13 | import org.springframework.context.ApplicationContextAware; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class DomainRegistry implements ApplicationContextAware { 18 | 19 | private static ApplicationContext applicationContext; 20 | 21 | public static EncryptionService encryptionService() { 22 | return (EncryptionService) applicationContext.getBean("MD5EncryptionService"); 23 | } 24 | 25 | public static PasswordService passwordService() { 26 | return (PasswordService) applicationContext.getBean("passwordService"); 27 | } 28 | 29 | public static TokenProvider tokenProvider() { 30 | return (TokenProvider) applicationContext.getBean("jwtTokenProvider"); 31 | } 32 | 33 | public static ModelMapper modelMapper() { 34 | return (ModelMapper) applicationContext.getBean("modelMapper"); 35 | } 36 | 37 | public static UserRepository userRepository() { 38 | return (UserRepository) applicationContext.getBean("userRepository"); 39 | } 40 | 41 | public static UserRegistrationRepository userRegistrationRepository() { 42 | return (UserRegistrationRepository) applicationContext.getBean("userRegistrationRepository"); 43 | } 44 | 45 | public static UserEmailMustBeUnique userEmailMustBeUnique(String anEmail) { 46 | return new UserEmailMustBeUnique(userRepository(), anEmail); 47 | } 48 | 49 | public static UserRegistrationMustBeUnique userRegistrationMustBeUnique(String anEmail) { 50 | return new UserRegistrationMustBeUnique(userRegistrationRepository(), anEmail); 51 | } 52 | 53 | @Override 54 | public void setApplicationContext(ApplicationContext anApplicationContext) throws BeansException { 55 | // if (DomainRegistry.applicationContext == null) { 56 | // DomainRegistry.applicationContext = anApplicationContext; 57 | // } 58 | 59 | DomainRegistry.applicationContext = anApplicationContext; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/EncryptionService.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain; 2 | 3 | public interface EncryptionService { 4 | 5 | String encryptedValue(String aPlainTextValue); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/oauth2/OAuth2Authentication.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.oauth2; 2 | 3 | public interface OAuth2Authentication { 4 | OAuth2Principal authenticate(String anAccessCode); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/oauth2/OAuth2Principal.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.oauth2; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | 6 | @Getter 7 | @NoArgsConstructor 8 | public class OAuth2Principal { 9 | private String id; 10 | private String email; 11 | private String firstName; 12 | private String lastName; 13 | private String imageUrl; 14 | private String provider; 15 | 16 | public OAuth2Principal(String id, String email, String firstName, String lastName, String imageUrl, String provider) { 17 | this.id = id; 18 | this.email = email; 19 | this.firstName = firstName; 20 | this.lastName = lastName; 21 | this.imageUrl = imageUrl; 22 | this.provider = provider; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/oauth2/OAuth2Service.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.oauth2; 2 | 3 | import com.tomo.ddd.domain.BusinessRuleValidationException; 4 | import com.tomo.mcauthentication.domain.users.User; 5 | import com.tomo.mcauthentication.domain.users.UserRepository; 6 | import com.tomo.mcauthentication.domain.users.rules.UserEmailMustBeUnique; 7 | 8 | public class OAuth2Service { 9 | 10 | private OAuth2Authentication oAuth2Authentication; 11 | private UserRepository userRespository; 12 | 13 | public OAuth2Service(OAuth2Authentication oAuth2Authentication, UserRepository userRespository) { 14 | this.oAuth2Authentication = oAuth2Authentication; 15 | this.userRespository = userRespository; 16 | } 17 | 18 | public User registerAuthenticate(String anAccessCode) { 19 | OAuth2Principal principal = oAuth2Authentication.authenticate(anAccessCode); 20 | User user; 21 | try { 22 | user = authenticateAndRegister(principal); 23 | } catch (BusinessRuleValidationException exception) { 24 | if (UserEmailMustBeUnique.class == exception.getBrokenRule().getClass()) { 25 | user = userRespository.findByEmail(principal.getEmail()); 26 | if (!User.AuthProvider.valueOf(principal.getProvider()).equals(user.getProvider())) { 27 | throw exception; 28 | } 29 | } else { 30 | throw exception; 31 | } 32 | } 33 | 34 | return user; 35 | } 36 | 37 | protected User authenticateAndRegister(OAuth2Principal principal) { 38 | User user = new User( 39 | userRespository.nextIdentity(), 40 | principal.getFirstName(), 41 | principal.getLastName(), 42 | principal.getEmail(), 43 | User.AuthProvider.valueOf(principal.getProvider())); 44 | 45 | return userRespository.save(user); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/EmailAuthenticationService.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration; 2 | 3 | import com.tomo.ddd.domain.BusinessRuleValidator; 4 | import com.tomo.mcauthentication.domain.EncryptionService; 5 | import com.tomo.mcauthentication.domain.registration.rules.PasswordsMustMatch; 6 | import com.tomo.mcauthentication.domain.users.User; 7 | import com.tomo.mcauthentication.domain.users.UserRepository; 8 | 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service 12 | public class EmailAuthenticationService extends BusinessRuleValidator { 13 | 14 | UserRegistrationRepository userRegistrationRepository; 15 | UserRepository userRepository; 16 | EncryptionService encryptionService; 17 | 18 | public EmailAuthenticationService( 19 | UserRegistrationRepository userRegistrationRepository, 20 | UserRepository userRepository, 21 | EncryptionService encryptionService) { 22 | this.userRegistrationRepository = userRegistrationRepository; 23 | this.userRepository = userRepository; 24 | this.encryptionService = encryptionService; 25 | } 26 | 27 | public User authenticate( 28 | String anEmail, 29 | String aPassword) { 30 | this.assertArgumentNotEmpty(anEmail, "Email must be provided."); 31 | this.assertArgumentNotEmpty(aPassword, "Password must be provided."); 32 | 33 | UserRegistration userRegistration = userRegistrationRepository.findByEmail(anEmail); 34 | 35 | if (userRegistration == null) { 36 | throw new IllegalStateException(String.format("User with email %s doesn't exists.", anEmail)); 37 | } 38 | 39 | this.checkRule(new PasswordsMustMatch(userRegistration.getPassword(), encryptionService.encryptedValue(aPassword))); 40 | 41 | return userRepository.findByEmail(anEmail); 42 | } 43 | 44 | public String createPasswordRecoveryCode(String anEmail) { 45 | this.assertArgumentNotEmpty(anEmail, "Email must be provided."); 46 | 47 | UserRegistration userRegistration = userRegistrationRepository.findByEmail(anEmail); 48 | 49 | if (userRegistration == null) { 50 | throw new IllegalStateException(String.format("User with email %s doesn't exists.", anEmail)); 51 | } 52 | 53 | return userRegistration.createRecoveryCode(); 54 | } 55 | 56 | public void recoverPasswordWithRecoveryCode(String aRecoveryCode, String aNewPassword, String aNewPasswordRepeated) { 57 | this.assertArgumentNotNull(aRecoveryCode, "Recovery code is missing."); 58 | 59 | UserRegistration userRegistration = userRegistrationRepository 60 | .findByRecoveryCode(encryptionService.encryptedValue(aRecoveryCode)); 61 | 62 | if (userRegistration == null) { 63 | throw new IllegalStateException(String.format("User with recovery code %s doesn't exists.", aRecoveryCode)); 64 | } 65 | 66 | userRegistration.changePasswordWithRecoveryCode(aRecoveryCode, aNewPassword, aNewPasswordRepeated); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/UserRegistrationId.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration; 2 | 3 | import com.tomo.ddd.domain.AbstractId; 4 | 5 | import javax.persistence.Embeddable; 6 | import java.util.UUID; 7 | 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | import lombok.Setter; 11 | 12 | @Embeddable 13 | @Getter 14 | @Setter 15 | @NoArgsConstructor 16 | public class UserRegistrationId extends AbstractId { 17 | 18 | public UserRegistrationId(UUID anId) { 19 | super(anId); 20 | } 21 | 22 | @Override 23 | protected int hashPrimeValue() { 24 | return 0; 25 | } 26 | 27 | @Override 28 | protected int hashOddValue() { 29 | return 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/UserRegistrationRepository.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration; 2 | 3 | import com.tomo.ddd.domain.BaseRepository; 4 | import com.tomo.mcauthentication.domain.users.UserId; 5 | 6 | import java.util.List; 7 | 8 | public interface UserRegistrationRepository extends BaseRepository { 9 | List findAllByEmail(List emails); 10 | UserRegistration findByEmail(String anEmail); 11 | long countByEmailAndStatus(String email, UserRegistrationStatus status); 12 | UserRegistration findByConfirmationCode(String confirmationCode); 13 | UserRegistration findByRecoveryCode(String aRecoveryCode); 14 | UserRegistration findByUserId(UserId anUserId); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/UserRegistrationStatus.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration; 2 | public enum 3 | UserRegistrationStatus { 4 | WaitingForConfirmation("WaitingForConfirmation"), 5 | Confirmed("Confirmed"), 6 | Expired("Expired"); 7 | 8 | String value; 9 | 10 | UserRegistrationStatus(String value) { 11 | this.value = value; 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return this.value; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/UsersCounter.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration; 2 | 3 | public interface UsersCounter { 4 | int countUsersWithLogin(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/events/PasswordChanged.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.events; 2 | 3 | import com.tomo.ddd.domain.BaseDomainEvent; 4 | 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | public class PasswordChanged extends BaseDomainEvent { 13 | private long userRegistrationId; 14 | private String password; //encrypted 15 | 16 | public PasswordChanged(long userRegistrationId, String password) { 17 | this.userRegistrationId = userRegistrationId; 18 | this.password = password; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/events/PasswordRecovered.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.events; 2 | 3 | import com.tomo.ddd.domain.BaseDomainEvent; 4 | 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | public class PasswordRecovered extends BaseDomainEvent { 13 | private long userRegistrationId; 14 | private String password; //encrypted 15 | private String recoveryCode; //encrypted 16 | 17 | public PasswordRecovered(long userRegistrationId, String password, String recoveryCode) { 18 | this.userRegistrationId = userRegistrationId; 19 | this.password = password; 20 | this.recoveryCode = recoveryCode; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/events/PasswordRecoveryCodeCreated.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.events; 2 | 3 | import com.tomo.ddd.domain.BaseDomainEvent; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class PasswordRecoveryCodeCreated extends BaseDomainEvent { 15 | long userRegistrationId; 16 | private String email; 17 | private String recoveryCode; 18 | private LocalDateTime recoveryCodeExpirationDate; 19 | 20 | public PasswordRecoveryCodeCreated(long userRegistrationId, String email, String recoveryCode, LocalDateTime recoveryCodeExpirationDate) { 21 | this.userRegistrationId = userRegistrationId; 22 | this.email = email; 23 | this.recoveryCode = recoveryCode; 24 | this.recoveryCodeExpirationDate = recoveryCodeExpirationDate; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/events/UserRegistrationConfirmed.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.events; 2 | 3 | import com.tomo.ddd.domain.BaseDomainEvent; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistrationStatus; 5 | import com.tomo.mcauthentication.domain.users.UserId; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class UserRegistrationConfirmed extends BaseDomainEvent { 15 | private long userRegistrationId; 16 | private UserRegistrationStatus status; 17 | private UserId userId; 18 | 19 | public UserRegistrationConfirmed(long userRegistrationId, UserRegistrationStatus status, UserId userId) { 20 | this.userRegistrationId = userRegistrationId; 21 | this.status = status; 22 | this.userId = userId; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/events/UserRegistrationRequested.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.events; 2 | 3 | import com.tomo.ddd.domain.BaseDomainEvent; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistrationStatus; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | import lombok.Setter; 11 | 12 | @Getter 13 | @Setter 14 | @NoArgsConstructor 15 | public class UserRegistrationRequested extends BaseDomainEvent { 16 | private long userRegistrationId; 17 | private String email; 18 | private String confirmationCode; 19 | private String firstName; 20 | private String lastName; 21 | private LocalDateTime registerDate; 22 | private UserRegistrationStatus status; 23 | 24 | public UserRegistrationRequested( 25 | String email, 26 | String confirmationCode, 27 | String firstName, 28 | String lastName, 29 | LocalDateTime registerDate, 30 | UserRegistrationStatus status) { 31 | this.email = email; 32 | this.confirmationCode = confirmationCode; 33 | this.firstName = firstName; 34 | this.lastName = lastName; 35 | this.registerDate = registerDate; 36 | this.status = status; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/rules/PasswordRecoveryCodeShouldBeExpiredOrNull.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.rules; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 5 | 6 | public class PasswordRecoveryCodeShouldBeExpiredOrNull implements BusinessRule { 7 | 8 | private UserRegistration userRegistration; 9 | 10 | public PasswordRecoveryCodeShouldBeExpiredOrNull(UserRegistration aUserRegistration) { 11 | this.userRegistration = aUserRegistration; 12 | } 13 | 14 | @Override 15 | public Boolean isRuleComplied() { 16 | return userRegistration.isRecoveryCodeExpired() || userRegistration.getRecoveryCode() == null; 17 | } 18 | 19 | @Override 20 | public String message() { 21 | return "User recovery code is not expired yet. You can't get new one after the current code expire."; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/rules/PasswordRecoveryCodeShouldNotExpired.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.rules; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 5 | 6 | public class PasswordRecoveryCodeShouldNotExpired implements BusinessRule { 7 | 8 | private UserRegistration userRegistration; 9 | 10 | public PasswordRecoveryCodeShouldNotExpired(UserRegistration aUserRegistration) { 11 | this.userRegistration = aUserRegistration; 12 | } 13 | 14 | @Override 15 | public Boolean isRuleComplied() { 16 | return userRegistration.isRecoveryCodeUnexpired(); 17 | } 18 | 19 | @Override 20 | public String message() { 21 | return "User recovery code is not expired yet. You can't get new one after the current code expire."; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/rules/PasswordsMustMatch.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.rules; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | 5 | public class PasswordsMustMatch implements BusinessRule { 6 | 7 | private String providedPassoword; 8 | private String storedPassword; 9 | 10 | public PasswordsMustMatch(String storedPassword, String providedPassoword) { 11 | this.storedPassword = storedPassword; 12 | this.providedPassoword = providedPassoword; 13 | } 14 | 15 | @Override 16 | public Boolean isRuleComplied() { 17 | return providedPassoword.equals(storedPassword); 18 | } 19 | 20 | @Override 21 | public String message() { 22 | return "Passwords dont match."; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/rules/RecoveryCodeMustMatch.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.rules; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | 5 | public class RecoveryCodeMustMatch implements BusinessRule { 6 | 7 | private String providedCode; 8 | private String storedCode; 9 | 10 | public RecoveryCodeMustMatch(String aStoredCode, String aProvidedCode) { 11 | this.storedCode = aStoredCode; 12 | this.providedCode = aProvidedCode; 13 | } 14 | 15 | @Override 16 | public Boolean isRuleComplied() { 17 | return providedCode.equals(storedCode); 18 | } 19 | 20 | @Override 21 | public String message() { 22 | return "Passwords dont match."; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/rules/UserRegistrationCannotBeConfirmedAfterExpiration.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.rules; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | public class UserRegistrationCannotBeConfirmedAfterExpiration implements BusinessRule { 8 | 9 | public static final int CONFIRMATION_LINK_DURATION = 8; 10 | 11 | LocalDateTime registerDate; 12 | 13 | public UserRegistrationCannotBeConfirmedAfterExpiration(LocalDateTime aRegisterDate) { 14 | this.registerDate = aRegisterDate; 15 | } 16 | 17 | @Override 18 | public Boolean isRuleComplied() { 19 | return LocalDateTime.now().isBefore(this.registerDate.plusDays(CONFIRMATION_LINK_DURATION)); 20 | } 21 | 22 | @Override 23 | public String message() { 24 | return null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/rules/UserRegistrationCannotBeConfirmedMoreThanOnce.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.rules; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistrationStatus; 5 | 6 | public class UserRegistrationCannotBeConfirmedMoreThanOnce implements BusinessRule { 7 | 8 | UserRegistrationStatus status; 9 | 10 | public UserRegistrationCannotBeConfirmedMoreThanOnce(UserRegistrationStatus aStatus) { 11 | this.status = aStatus; 12 | } 13 | 14 | @Override 15 | public Boolean isRuleComplied() { 16 | return !this.status.equals(UserRegistrationStatus.Confirmed); 17 | } 18 | 19 | @Override 20 | public String message() { 21 | return "User Registration cannot be confirmed more than once"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/rules/UserRegistrationMustBeConfirmed.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.rules; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistrationStatus; 5 | 6 | public class UserRegistrationMustBeConfirmed implements BusinessRule { 7 | 8 | private UserRegistrationStatus userRegistrationStatus; 9 | 10 | public UserRegistrationMustBeConfirmed(UserRegistrationStatus anUserRegistrationStatus) { 11 | this.userRegistrationStatus = anUserRegistrationStatus; 12 | } 13 | 14 | @Override 15 | public Boolean isRuleComplied() { 16 | return userRegistrationStatus.equals(UserRegistrationStatus.Confirmed); 17 | } 18 | 19 | @Override 20 | public String message() { 21 | return "User registration is not confirmed yet."; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/registration/rules/UserRegistrationMustBeUnique.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.registration.rules; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistrationRepository; 5 | import com.tomo.mcauthentication.domain.registration.UserRegistrationStatus; 6 | 7 | public class UserRegistrationMustBeUnique implements BusinessRule { 8 | 9 | private UserRegistrationRepository repository; 10 | private String email; 11 | 12 | public UserRegistrationMustBeUnique(UserRegistrationRepository usersCounter, String email) { 13 | this.repository = usersCounter; 14 | this.email = email; 15 | } 16 | 17 | @Override 18 | public Boolean isRuleComplied() { 19 | return repository.countByEmailAndStatus(email, UserRegistrationStatus.Confirmed) < 1; 20 | } 21 | 22 | @Override 23 | public String message() { 24 | return "User login must be unique"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/session/Session.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.session; 2 | 3 | import com.tomo.ddd.domain.DomainEventPublisher; 4 | import com.tomo.ddd.domain.RootEntity; 5 | import com.tomo.mcauthentication.domain.DomainRegistry; 6 | import com.tomo.mcauthentication.domain.session.events.SessionCreated; 7 | import com.tomo.mcauthentication.domain.users.User; 8 | import com.tomo.mcauthentication.domain.users.UserId; 9 | 10 | import javax.persistence.AttributeOverride; 11 | import javax.persistence.Column; 12 | import javax.persistence.Embedded; 13 | import javax.persistence.EmbeddedId; 14 | import javax.persistence.Entity; 15 | import javax.persistence.EnumType; 16 | import javax.persistence.Enumerated; 17 | import java.time.LocalDateTime; 18 | import java.time.temporal.ChronoField; 19 | 20 | import lombok.Getter; 21 | import lombok.NoArgsConstructor; 22 | import lombok.Setter; 23 | 24 | @Entity 25 | @NoArgsConstructor 26 | @Getter 27 | @Setter 28 | public class Session extends RootEntity { 29 | 30 | public static Long EXPIRATION_MSEC = 15000L; 31 | 32 | public enum TokenType { 33 | CLIENT_SECRET_JWT, 34 | PRIVATE_KEY_JWT, 35 | BASIC, 36 | API_KEY 37 | } 38 | 39 | @EmbeddedId 40 | private SessionId sessionId; 41 | private String accessToken; 42 | private LocalDateTime expirationDate; 43 | 44 | @Enumerated(EnumType.STRING) 45 | private TokenType tokenType; 46 | private String refreshToken; 47 | private String userAgent; 48 | private String ipAddress; 49 | private LocalDateTime lastActivity; 50 | 51 | @Embedded 52 | @AttributeOverride(name="id", column = @Column(name="user_id")) 53 | private UserId userId; 54 | 55 | public Session(SessionId sessionId, User user, TokenProvider tokenProvider, Boolean rememberMe, String userAgent, String ipAddress) 56 | { 57 | this.sessionId = sessionId; 58 | this.ipAddress = ipAddress; 59 | this.userAgent = userAgent; 60 | this.tokenType = tokenProvider.getTokenType(); 61 | this.userId = user.getUserId(); 62 | this.expirationDate = LocalDateTime.now().plus(EXPIRATION_MSEC, ChronoField.MILLI_OF_DAY.getBaseUnit()); 63 | this.accessToken = tokenProvider.createToken(user); 64 | 65 | if (Boolean.TRUE.equals(rememberMe)) { 66 | this.refreshToken = tokenProvider.createRefreshToken(user); 67 | } 68 | 69 | DomainEventPublisher.instance().publish( 70 | new SessionCreated(this.getSessionId(), this.getUserId()) 71 | ); 72 | } 73 | 74 | public boolean isExpired() { 75 | return !expirationDate.isAfter(LocalDateTime.now()); 76 | } 77 | 78 | private void protectedAccessToken(String anToken) { 79 | this.assertArgumentNotEmpty(anToken, "Access token cannot be empty."); 80 | this.setAccessToken(DomainRegistry.encryptionService().encryptedValue(anToken)); 81 | } 82 | 83 | private void protectedRefreshToken(String anToken) { 84 | this.assertArgumentNotEmpty(anToken, "Refresh token cannot be empty."); 85 | this.setRefreshToken(DomainRegistry.encryptionService().encryptedValue(anToken)); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/session/SessionAuthenticationService.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.session; 2 | 3 | import com.tomo.ddd.domain.BusinessRuleValidator; 4 | import com.tomo.mcauthentication.domain.session.rule.SessionCannotBeExpiredWhenRefreshTokenIsMissing; 5 | import com.tomo.mcauthentication.domain.users.UserRepository; 6 | 7 | import org.springframework.beans.factory.annotation.Qualifier; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | @Service 13 | public class SessionAuthenticationService extends BusinessRuleValidator { 14 | 15 | TokenProvider tokenProvider; 16 | SessionRepository sessionRepository; 17 | UserRepository userRepository; 18 | 19 | public SessionAuthenticationService( 20 | TokenProvider tokenProvider, 21 | SessionRepository sessionRepository, 22 | @Qualifier("userRepositoryJpaAdapter") UserRepository userRepository) { 23 | this.tokenProvider = tokenProvider; 24 | this.sessionRepository = sessionRepository; 25 | this.userRepository = userRepository; 26 | } 27 | 28 | public Session authenticate(String anAccessToken) { 29 | assertArgumentNotEmpty(anAccessToken, "Session token cannot be empty."); 30 | 31 | Session session = sessionRepository.findByAccessToken(anAccessToken); 32 | if (session == null) { 33 | throw new IllegalStateException(String.format("Session with access code %s doesn't exist.", anAccessToken)); 34 | } 35 | 36 | checkRule(new SessionCannotBeExpiredWhenRefreshTokenIsMissing(session)); 37 | 38 | if (session.isExpired()) { 39 | return new Session( 40 | sessionRepository.nextIdentity(), 41 | userRepository.findById(session.getUserId()), 42 | tokenProvider, 43 | true, 44 | session.getUserAgent(), 45 | session.getIpAddress()); 46 | } 47 | 48 | session.setLastActivity(LocalDateTime.now()); 49 | return session; 50 | } 51 | 52 | public Session logout(String anAccessToken) { 53 | assertArgumentNotEmpty(anAccessToken, "Session token cannot be empty."); 54 | 55 | Session session = sessionRepository.findByAccessToken(anAccessToken); 56 | if (session == null) { 57 | throw new IllegalStateException(String.format("Session with access code %s doesn't exist.", anAccessToken)); 58 | } 59 | 60 | session.setExpirationDate(LocalDateTime.now()); 61 | session.setRefreshToken(null); 62 | 63 | return sessionRepository.save(session); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/session/SessionId.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.session; 2 | 3 | import com.tomo.ddd.domain.AbstractId; 4 | 5 | import javax.persistence.Embeddable; 6 | import java.util.UUID; 7 | 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | import lombok.Setter; 11 | 12 | @Embeddable 13 | @Getter 14 | @Setter 15 | @NoArgsConstructor 16 | public class SessionId extends AbstractId { 17 | 18 | public SessionId(UUID id) { 19 | super(id); 20 | } 21 | 22 | @Override 23 | protected int hashOddValue() { 24 | return 5785; 25 | } 26 | 27 | @Override 28 | protected int hashPrimeValue() { 29 | return 31; 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/session/SessionRepository.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.session; 2 | 3 | import com.tomo.ddd.domain.BaseRepository; 4 | import com.tomo.mcauthentication.domain.users.UserId; 5 | 6 | import java.util.List; 7 | 8 | public interface SessionRepository extends BaseRepository { 9 | SessionId nextIdentity(); 10 | List findByUserId(UserId userId); 11 | Session findByAccessToken(String anAccessToken); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/session/TokenProvider.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.session; 2 | 3 | import com.tomo.mcauthentication.domain.users.User; 4 | import com.tomo.mcauthentication.domain.users.UserId; 5 | 6 | public interface TokenProvider { 7 | String createToken(User user); 8 | String createRefreshToken(User user); 9 | UserId getUserIdFromToken(String anAuthToken); 10 | boolean validateToken(String anAuthToken); 11 | Session.TokenType getTokenType(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/session/events/SessionCreated.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.session.events; 2 | 3 | import com.tomo.ddd.domain.BaseDomainEvent; 4 | import com.tomo.mcauthentication.domain.session.SessionId; 5 | import com.tomo.mcauthentication.domain.users.UserId; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class SessionCreated extends BaseDomainEvent { 15 | private SessionId sessionId; 16 | private UserId userId; 17 | 18 | public SessionCreated(SessionId sessionId, UserId userId) { 19 | this.sessionId = sessionId; 20 | this.userId = userId; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/session/rule/SessionCannotBeExpiredWhenRefreshTokenIsMissing.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.session.rule; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | import com.tomo.mcauthentication.domain.session.Session; 5 | 6 | public class SessionCannotBeExpiredWhenRefreshTokenIsMissing implements BusinessRule { 7 | 8 | Session session; 9 | 10 | public SessionCannotBeExpiredWhenRefreshTokenIsMissing(Session session) { 11 | this.session = session; 12 | } 13 | 14 | @Override 15 | public Boolean isRuleComplied() { 16 | return (!session.isExpired()) || (session.isExpired() && session.getRefreshToken() != null); 17 | } 18 | 19 | @Override 20 | public String message() { 21 | return String.format("Session token is expired and refresh token is missing."); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/users/EmailLogin.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.users; 2 | 3 | public class EmailLogin { 4 | User user; 5 | String username; 6 | String password; 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/users/User.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.users; 2 | 3 | import com.tomo.ddd.domain.ConcurrencySafeEntity; 4 | import com.tomo.ddd.domain.DomainEvent; 5 | import com.tomo.ddd.domain.DomainEventPublisher; 6 | import com.tomo.mcauthentication.domain.DomainRegistry; 7 | import com.tomo.mcauthentication.domain.users.events.UserCreated; 8 | import com.tomo.mcauthentication.domain.users.events.UserNameChanged; 9 | 10 | import javax.persistence.EmbeddedId; 11 | import javax.persistence.Entity; 12 | import javax.persistence.EnumType; 13 | import javax.persistence.Enumerated; 14 | 15 | import lombok.Getter; 16 | import lombok.NoArgsConstructor; 17 | 18 | @Entity(name = "mcuser") 19 | @Getter 20 | @NoArgsConstructor 21 | public class User extends ConcurrencySafeEntity { 22 | 23 | public enum AuthProvider { 24 | EMAIL, 25 | FACEBOOK, 26 | GOOGLE 27 | } 28 | 29 | @EmbeddedId 30 | UserId userId; 31 | String firstName; 32 | String lastName; 33 | String email; 34 | 35 | @Enumerated(EnumType.STRING) 36 | AuthProvider provider; 37 | 38 | public User( 39 | UserId anId, 40 | String aFirstName, 41 | String aLastName, 42 | String anEmail, 43 | AuthProvider aProvider) { 44 | this.checkRule(DomainRegistry.userEmailMustBeUnique(anEmail)); 45 | this.userId = anId; 46 | this.firstName = aFirstName; 47 | this.lastName = aLastName; 48 | this.email = anEmail; 49 | this.provider = aProvider; 50 | 51 | this.publish(new UserCreated( 52 | this.getUserId(), 53 | this.getFirstName(), 54 | this.getLastName(), 55 | this.getEmail(), 56 | this.getProvider() 57 | )); 58 | } 59 | 60 | public void updateDetails(String aFirstName, String aLastName) { 61 | this.setFirstName(aFirstName); 62 | this.setLastName(aLastName); 63 | 64 | publish(new UserNameChanged( 65 | this.getEmail(), 66 | this.getFirstName(), 67 | this.getLastName())); 68 | } 69 | 70 | public void setLastName(String aLastName) { 71 | assertArgumentNotEmpty(lastName, "Last name cannot be empty."); 72 | this.lastName = aLastName; 73 | } 74 | 75 | public void setFirstName(String aFirstName) { 76 | assertArgumentNotEmpty(aFirstName, "First name cannot be empty."); 77 | this.firstName = aFirstName; 78 | } 79 | 80 | private void publish(DomainEvent event) { 81 | DomainEventPublisher.instance().publish(event); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/users/UserId.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.users; 2 | 3 | import com.tomo.ddd.domain.AbstractId; 4 | 5 | import javax.persistence.Embeddable; 6 | 7 | import java.util.UUID; 8 | 9 | import lombok.Getter; 10 | import lombok.NoArgsConstructor; 11 | import lombok.Setter; 12 | 13 | @Embeddable 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | public class UserId extends AbstractId { 18 | 19 | public UserId(UUID id) { 20 | super(id); 21 | } 22 | 23 | public UserId(String id) { 24 | super(UUID.fromString(id)); 25 | } 26 | 27 | @Override 28 | protected int hashOddValue() { 29 | return 83811; 30 | } 31 | 32 | @Override 33 | protected int hashPrimeValue() { 34 | return 263; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/users/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.users; 2 | 3 | import com.tomo.ddd.domain.BaseRepository; 4 | 5 | public interface UserRepository extends BaseRepository { 6 | UserId nextIdentity(); 7 | User findByEmail(String anEmail); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/users/events/UserCreated.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.users.events; 2 | 3 | import com.tomo.ddd.domain.BaseDomainEvent; 4 | import com.tomo.mcauthentication.domain.users.User; 5 | import com.tomo.mcauthentication.domain.users.UserId; 6 | 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | public class UserCreated extends BaseDomainEvent { 15 | UserId userId; 16 | String firstName; 17 | String lastName; 18 | String email; 19 | User.AuthProvider provider; 20 | 21 | public UserCreated(UserId userId, String firstName, String lastName, String email, User.AuthProvider provider) { 22 | this.userId = userId; 23 | this.firstName = firstName; 24 | this.lastName = lastName; 25 | this.email = email; 26 | this.provider = provider; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/users/events/UserNameChanged.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.users.events; 2 | 3 | import com.tomo.ddd.domain.BaseDomainEvent; 4 | 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | public class UserNameChanged extends BaseDomainEvent { 13 | String email; 14 | String firstName; 15 | String lastName; 16 | 17 | public UserNameChanged(String email, String firstName, String lastName) { 18 | this.email = email; 19 | this.firstName = firstName; 20 | this.lastName = lastName; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/domain/users/rules/UserEmailMustBeUnique.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.domain.users.rules; 2 | 3 | import com.tomo.ddd.domain.BusinessRule; 4 | import com.tomo.mcauthentication.domain.users.UserRepository; 5 | 6 | public class UserEmailMustBeUnique implements BusinessRule { 7 | 8 | UserRepository userRespository; 9 | String email; 10 | 11 | public UserEmailMustBeUnique(UserRepository userRespository, String email) { 12 | this.userRespository = userRespository; 13 | this.email = email; 14 | } 15 | 16 | @Override 17 | public Boolean isRuleComplied() { 18 | return userRespository.findByEmail(this.email) == null; 19 | } 20 | 21 | @Override 22 | public String message() { 23 | return "User with this email already exists."; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/McAuthenticationModuleExecutor.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure; 2 | 3 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 4 | import com.tomo.mcauthentication.application.configuration.QueryHandler; 5 | import com.tomo.mcauthentication.application.contracts.Command; 6 | import com.tomo.mcauthentication.application.contracts.McAuthenticationModule; 7 | import com.tomo.mcauthentication.application.contracts.Query; 8 | import com.tomo.mcauthentication.application.contracts.Response; 9 | import com.tomo.mcauthentication.infrastructure.processing.builder.CommandHandlerPipelineBuilder; 10 | import com.tomo.mcauthentication.infrastructure.processing.builder.QueryHandlerPipelineBuilder; 11 | 12 | import org.springframework.stereotype.Component; 13 | 14 | @Component 15 | public class McAuthenticationModuleExecutor implements McAuthenticationModule { 16 | 17 | CommandHandlerPipelineBuilder commandHandlerPipelineBuilder; 18 | QueryHandlerPipelineBuilder queryHandlerPipelineBuilder; 19 | 20 | 21 | public McAuthenticationModuleExecutor( 22 | CommandHandlerPipelineBuilder commandHandlerPipelineBuilder, 23 | QueryHandlerPipelineBuilder queryHandlerPipelineBuilder) { 24 | this.commandHandlerPipelineBuilder = commandHandlerPipelineBuilder; 25 | this.queryHandlerPipelineBuilder = queryHandlerPipelineBuilder; 26 | } 27 | 28 | @Override 29 | public Response executeCommand(Command command) { 30 | CommandHandler commandHandler = commandHandlerPipelineBuilder 31 | .with(command) 32 | .build(); 33 | 34 | return commandHandler.handle(command); 35 | } 36 | 37 | @Override 38 | public Response executeQuery(Query query) { 39 | QueryHandler queryHandler = queryHandlerPipelineBuilder 40 | .with(query) 41 | .build(); 42 | 43 | return queryHandler.handle(query); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/http/oauth2/AbstractOAuth2Authentication.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.http.oauth2; 2 | 3 | import com.tomo.mcauthentication.domain.oauth2.OAuth2Principal; 4 | import com.tomo.mcauthentication.infrastructure.http.oauth2.user.OAuth2UserInfo; 5 | import com.tomo.mcauthentication.infrastructure.http.oauth2.user.OAuth2UserInfoFactory; 6 | 7 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 8 | import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; 9 | import org.springframework.security.oauth2.core.OAuth2AccessToken; 10 | import org.springframework.security.oauth2.core.user.OAuth2User; 11 | 12 | import java.time.Instant; 13 | 14 | public abstract class AbstractOAuth2Authentication { 15 | 16 | ClientRegistration clientRegistration; 17 | CustomOAuth2UserService customOAuth2UserService; 18 | 19 | public AbstractOAuth2Authentication(ClientRegistration clientRegistration, 20 | CustomOAuth2UserService customOAuth2UserService) { 21 | this.clientRegistration = clientRegistration; 22 | this.customOAuth2UserService = customOAuth2UserService; 23 | } 24 | 25 | protected OAuth2Principal authenticateUser(String anAccessCode) { 26 | OAuth2UserRequest oAuth2UserRequest = new OAuth2UserRequest(clientRegistration, new OAuth2AccessToken( 27 | OAuth2AccessToken.TokenType.BEARER, 28 | anAccessCode, 29 | Instant.now(), Instant.now().plusSeconds(10000L))); 30 | OAuth2User oAuth2User = customOAuth2UserService.loadUser(oAuth2UserRequest); 31 | OAuth2UserInfo userInfo = OAuth2UserInfoFactory 32 | .getOAuth2UserInfo(clientRegistration.getRegistrationId(), oAuth2User.getAttributes()); 33 | return new OAuth2Principal( 34 | userInfo.getId(), 35 | userInfo.getEmail(), 36 | userInfo.getName(), 37 | userInfo.getName(), 38 | userInfo.getImageUrl(), 39 | clientRegistration.getRegistrationId()); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/http/oauth2/CustomOAuth2UserService.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.http.oauth2; 2 | 3 | import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; 4 | import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; 5 | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; 6 | import org.springframework.security.oauth2.core.user.OAuth2User; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class CustomOAuth2UserService extends DefaultOAuth2UserService { 11 | 12 | public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException { 13 | return super.loadUser(oAuth2UserRequest); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/http/oauth2/FacebookOAuth2Authentication.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.http.oauth2; 2 | 3 | import com.tomo.mcauthentication.domain.oauth2.OAuth2Authentication; 4 | import com.tomo.mcauthentication.domain.oauth2.OAuth2Principal; 5 | import com.tomo.mcauthentication.infrastructure.http.oauth2.user.FacebookOAuth2UserInfo; 6 | import com.tomo.mcauthentication.infrastructure.http.oauth2.user.OAuth2UserInfoFactory; 7 | 8 | import org.springframework.beans.factory.annotation.Qualifier; 9 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 10 | import org.springframework.security.oauth2.core.user.OAuth2User; 11 | import org.springframework.stereotype.Service; 12 | 13 | @Service 14 | public class FacebookOAuth2Authentication extends AbstractOAuth2Authentication implements OAuth2Authentication { 15 | 16 | public FacebookOAuth2Authentication( 17 | @Qualifier("facebookClientRegistration") ClientRegistration clientRegistration, 18 | CustomOAuth2UserService customOAuth2UserService) { 19 | super(clientRegistration, customOAuth2UserService); 20 | } 21 | 22 | @Override 23 | public OAuth2Principal authenticate(String anAccessCode) { 24 | return super.authenticateUser(anAccessCode); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/http/oauth2/GoogleOAuth2Authentication.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.http.oauth2; 2 | 3 | import com.tomo.mcauthentication.domain.oauth2.OAuth2Authentication; 4 | import com.tomo.mcauthentication.domain.oauth2.OAuth2Principal; 5 | import com.tomo.mcauthentication.infrastructure.http.oauth2.user.FacebookOAuth2UserInfo; 6 | import com.tomo.mcauthentication.infrastructure.http.oauth2.user.OAuth2UserInfoFactory; 7 | 8 | import org.springframework.beans.factory.annotation.Qualifier; 9 | import org.springframework.security.oauth2.client.registration.ClientRegistration; 10 | import org.springframework.security.oauth2.core.user.OAuth2User; 11 | import org.springframework.stereotype.Service; 12 | 13 | @Service 14 | public class GoogleOAuth2Authentication extends AbstractOAuth2Authentication implements OAuth2Authentication { 15 | 16 | public GoogleOAuth2Authentication( 17 | @Qualifier("googleClientRegistration") ClientRegistration clientRegistration, 18 | CustomOAuth2UserService customOAuth2UserService) { 19 | super(clientRegistration, customOAuth2UserService); 20 | } 21 | 22 | @Override 23 | public OAuth2Principal authenticate(String anAccessCode) { 24 | return super.authenticateUser(anAccessCode); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/http/oauth2/user/FacebookOAuth2UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.http.oauth2.user; 2 | 3 | import java.util.Map; 4 | 5 | public class FacebookOAuth2UserInfo extends OAuth2UserInfo { 6 | public FacebookOAuth2UserInfo(Map attributes) { 7 | super(attributes); 8 | } 9 | 10 | @Override 11 | public String getId() { 12 | return (String) attributes.get("id"); 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return (String) attributes.get("name"); 18 | } 19 | 20 | @Override 21 | public String getEmail() { 22 | return (String) attributes.get("email"); 23 | } 24 | 25 | @Override 26 | public String getImageUrl() { 27 | if(attributes.containsKey("picture")) { 28 | Map pictureObj = (Map) attributes.get("picture"); 29 | if(pictureObj.containsKey("data")) { 30 | Map dataObj = (Map) pictureObj.get("data"); 31 | if(dataObj.containsKey("url")) { 32 | return (String) dataObj.get("url"); 33 | } 34 | } 35 | } 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/http/oauth2/user/GoogleOAuth2UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.http.oauth2.user; 2 | 3 | import java.util.Map; 4 | 5 | public class GoogleOAuth2UserInfo extends OAuth2UserInfo { 6 | 7 | public GoogleOAuth2UserInfo(Map attributes) { 8 | super(attributes); 9 | } 10 | 11 | @Override 12 | public String getId() { 13 | return (String) attributes.get("sub"); 14 | } 15 | 16 | @Override 17 | public String getName() { 18 | return (String) attributes.get("name"); 19 | } 20 | 21 | @Override 22 | public String getEmail() { 23 | return (String) attributes.get("email"); 24 | } 25 | 26 | @Override 27 | public String getImageUrl() { 28 | return (String) attributes.get("picture"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/http/oauth2/user/OAuth2UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.http.oauth2.user; 2 | 3 | import java.util.Map;; 4 | 5 | public abstract class OAuth2UserInfo { 6 | protected Map attributes; 7 | 8 | public OAuth2UserInfo(Map attributes) { 9 | this.attributes = attributes; 10 | } 11 | 12 | public Map getAttributes() { 13 | return attributes; 14 | } 15 | 16 | public abstract String getId(); 17 | 18 | public abstract String getName(); 19 | 20 | public abstract String getEmail(); 21 | 22 | public abstract String getImageUrl(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/http/oauth2/user/OAuth2UserInfoFactory.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.http.oauth2.user; 2 | 3 | import com.tomo.mcauthentication.domain.users.User; 4 | 5 | import java.util.Map; 6 | 7 | public class OAuth2UserInfoFactory { 8 | 9 | public static OAuth2UserInfo getOAuth2UserInfo(String registrationId, Map attributes) { 10 | if(registrationId.equalsIgnoreCase(User.AuthProvider.GOOGLE.toString().toLowerCase())) { 11 | return new GoogleOAuth2UserInfo(attributes); 12 | } else if (registrationId.equalsIgnoreCase(User.AuthProvider.FACEBOOK.toString().toLowerCase())) { 13 | return new FacebookOAuth2UserInfo(attributes); 14 | } else { 15 | throw new IllegalArgumentException("Sorry! Login with " + registrationId + " is not supported yet."); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/persistence/BaseJpaAdapter.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.persistence; 2 | 3 | import com.tomo.ddd.domain.BaseRepository; 4 | import com.tomo.ddd.infrastructure.persistence.springdata.jpa.McCrudRepository; 5 | 6 | import java.util.List; 7 | import java.util.Optional; 8 | 9 | //https://github.com/benthurley82/generic-type-resolver-test/blob/main/src/main/java/com/example/test/AbstractFoo.java 10 | public class BaseJpaAdapter implements BaseRepository { 11 | 12 | protected E jpaRepository; 13 | 14 | public BaseJpaAdapter(E jpaRepository) { 15 | this.jpaRepository = jpaRepository; 16 | } 17 | 18 | @Override 19 | public T save(T entity) { 20 | return (T) jpaRepository.save(entity); 21 | } 22 | 23 | @Override 24 | public T findById(ID id) { 25 | Optional entity = jpaRepository.findById(id); 26 | return entity.isPresent() ? entity.get() : null; 27 | } 28 | 29 | @Override 30 | public List findAll() { 31 | return jpaRepository.findAll(); 32 | } 33 | 34 | @Override 35 | public void saveAll(List entities) { 36 | jpaRepository.saveAll(entities); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/persistence/SessionJpaRepository.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.persistence; 2 | 3 | import com.tomo.ddd.infrastructure.persistence.springdata.jpa.McCrudRepository; 4 | import com.tomo.mcauthentication.domain.session.Session; 5 | import com.tomo.mcauthentication.domain.session.SessionId; 6 | import com.tomo.mcauthentication.domain.users.UserId; 7 | 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.util.List; 11 | 12 | @Repository 13 | public interface SessionJpaRepository extends McCrudRepository { 14 | 15 | List findAllByUserId(UserId userId); 16 | 17 | Session findSessionByAccessToken(String accessToken); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/persistence/SessionRepositoryJpaAdapter.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.persistence; 2 | 3 | import com.tomo.mcauthentication.domain.session.Session; 4 | import com.tomo.mcauthentication.domain.session.SessionId; 5 | import com.tomo.mcauthentication.domain.session.SessionRepository; 6 | import com.tomo.mcauthentication.domain.users.UserId; 7 | 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.util.List; 11 | import java.util.UUID; 12 | 13 | @Repository 14 | public class SessionRepositoryJpaAdapter extends BaseJpaAdapter implements SessionRepository { 15 | 16 | public SessionRepositoryJpaAdapter(SessionJpaRepository jpaRepository) { 17 | super(jpaRepository); 18 | } 19 | 20 | @Override 21 | public SessionId nextIdentity() { 22 | return new SessionId(UUID.randomUUID()); 23 | } 24 | 25 | @Override 26 | public List findByUserId(UserId userId) { 27 | return jpaRepository.findAllByUserId(userId); 28 | } 29 | 30 | @Override 31 | public Session findByAccessToken(String anAccessToken) { 32 | return jpaRepository.findSessionByAccessToken(anAccessToken); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/persistence/UserJpaRepository.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.persistence; 2 | 3 | import com.tomo.ddd.infrastructure.persistence.springdata.jpa.McCrudRepository; 4 | import com.tomo.mcauthentication.domain.users.User; 5 | import com.tomo.mcauthentication.domain.users.UserId; 6 | 7 | import org.springframework.stereotype.Repository; 8 | 9 | @Repository 10 | public interface UserJpaRepository extends McCrudRepository { 11 | 12 | User findUserByEmail(String email); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/persistence/UserRegistrationJpaRepository.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.persistence; 2 | 3 | import com.tomo.ddd.infrastructure.persistence.springdata.jpa.McCrudRepository; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 5 | import com.tomo.mcauthentication.domain.users.UserId; 6 | 7 | import org.springframework.beans.factory.annotation.Qualifier; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.util.List; 11 | 12 | @Repository 13 | @Qualifier("UserRegistrationJpaRepository") 14 | public interface UserRegistrationJpaRepository extends McCrudRepository { 15 | 16 | long countByEmail(String email); 17 | 18 | List findAllByEmailIn(List email); 19 | 20 | UserRegistration findUserRegistrationByConfirmationCode(String confirmLink); 21 | 22 | UserRegistration findUserRegistrationByEmail(String email); 23 | 24 | UserRegistration findUserRegistrationByRecoveryCode(String recoveryCode); 25 | 26 | UserRegistration findUserRegistrationByUserId(UserId userId); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/persistence/UserRegistrationJpaRepositoryAdapter.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.persistence; 2 | 3 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 4 | import com.tomo.mcauthentication.domain.registration.UserRegistrationRepository; 5 | import com.tomo.mcauthentication.domain.registration.UserRegistrationStatus; 6 | import com.tomo.mcauthentication.domain.users.UserId; 7 | 8 | import java.util.List; 9 | 10 | public class UserRegistrationJpaRepositoryAdapter 11 | extends BaseJpaAdapter 12 | implements UserRegistrationRepository { 13 | 14 | public UserRegistrationJpaRepositoryAdapter(UserRegistrationJpaRepository jpaRepository) { 15 | super(jpaRepository); 16 | } 17 | 18 | @Override 19 | public long countByEmailAndStatus(String email, UserRegistrationStatus status) { 20 | return jpaRepository.countByEmail(email); 21 | } 22 | 23 | @Override 24 | public List findAllByEmail(List emails) { 25 | return jpaRepository.findAllByEmailIn(emails); 26 | } 27 | 28 | @Override 29 | public UserRegistration findByEmail(String anEmail) { 30 | return jpaRepository.findUserRegistrationByEmail(anEmail); 31 | } 32 | 33 | @Override public UserRegistration findByConfirmationCode(String confirmationCode) { 34 | return jpaRepository.findUserRegistrationByConfirmationCode(confirmationCode); 35 | } 36 | 37 | @Override 38 | public UserRegistration findByRecoveryCode(String aRecoveryCode) { 39 | return jpaRepository.findUserRegistrationByRecoveryCode(aRecoveryCode); 40 | } 41 | 42 | @Override public UserRegistration findByUserId(UserId anUserId) { 43 | return jpaRepository.findUserRegistrationByUserId(anUserId); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/persistence/UserRepositoryJpaAdapter.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.persistence; 2 | 3 | import com.tomo.mcauthentication.domain.users.User; 4 | import com.tomo.mcauthentication.domain.users.UserId; 5 | import com.tomo.mcauthentication.domain.users.UserRepository; 6 | 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.UUID; 10 | 11 | @Component 12 | public class UserRepositoryJpaAdapter extends BaseJpaAdapter implements UserRepository { 13 | 14 | public UserRepositoryJpaAdapter(UserJpaRepository userJpaRepository) { 15 | super(userJpaRepository); 16 | } 17 | 18 | @Override 19 | public UserId nextIdentity() { 20 | return new UserId(UUID.randomUUID()); 21 | } 22 | 23 | @Override 24 | public User findByEmail(String anEmail) { 25 | return jpaRepository.findUserByEmail(anEmail); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/processing/ErrorCommandHandlerDecorator.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.processing; 2 | 3 | import com.tomo.mcauthentication.application.configuration.AbstractVoidyCommandHandler; 4 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 5 | import com.tomo.mcauthentication.application.contracts.Command; 6 | 7 | public class ErrorCommandHandlerDecorator extends AbstractVoidyCommandHandler { 8 | 9 | CommandHandler commandHandler; 10 | 11 | public ErrorCommandHandlerDecorator(CommandHandler commandHandler) { 12 | this.commandHandler = commandHandler; 13 | } 14 | 15 | @Override 16 | protected void abstractHandle(T aCommand) { 17 | 18 | commandHandler.handle(aCommand); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/processing/LoggingCommandHandlerDecorator.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.processing; 2 | 3 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 4 | import com.tomo.mcauthentication.application.contracts.Command; 5 | import com.tomo.mcauthentication.application.contracts.Response; 6 | 7 | public class LoggingCommandHandlerDecorator implements CommandHandler { 8 | 9 | CommandHandler commandHandler; 10 | 11 | public LoggingCommandHandlerDecorator(CommandHandler commandHandler) { 12 | this.commandHandler = commandHandler; 13 | } 14 | 15 | @Override 16 | public Response handle(Command aCommand) { 17 | //todo log 18 | return commandHandler.handle(aCommand); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/processing/LoggingQueryHandlerDecorator.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.processing; 2 | 3 | import com.tomo.mcauthentication.application.configuration.QueryHandler; 4 | import com.tomo.mcauthentication.application.contracts.Query; 5 | import com.tomo.mcauthentication.application.contracts.Response; 6 | 7 | public class LoggingQueryHandlerDecorator implements QueryHandler { 8 | 9 | QueryHandler queryHandler; 10 | 11 | public LoggingQueryHandlerDecorator(QueryHandler queryHandler) { 12 | this.queryHandler = queryHandler; 13 | } 14 | 15 | @Override 16 | public Response handle(Query query) { 17 | return queryHandler.handle(query); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/processing/PipelineBuilder.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.processing; 2 | 3 | public interface PipelineBuilder { 4 | PipelineBuilder with(C aRequest); 5 | R build(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/processing/builder/AbstractPipelineBuilder.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.processing.builder; 2 | 3 | import com.tomo.mcauthentication.application.configuration.RequestHandler; 4 | import com.tomo.mcauthentication.application.contracts.Request; 5 | import com.tomo.mcauthentication.infrastructure.processing.PipelineBuilder; 6 | 7 | import org.springframework.beans.BeansException; 8 | import org.springframework.context.ApplicationContext; 9 | import org.springframework.context.ApplicationContextAware; 10 | 11 | public abstract class AbstractPipelineBuilder implements PipelineBuilder, ApplicationContextAware { 12 | 13 | protected E request; 14 | protected S handler; 15 | 16 | protected ApplicationContext applicationContext; 17 | 18 | @Override 19 | public PipelineBuilder with(E aRequest) { 20 | this.request = aRequest; 21 | this.handler = this.getHandler(); 22 | return this; 23 | } 24 | 25 | @Override 26 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 27 | this.applicationContext = applicationContext; 28 | } 29 | 30 | protected S getHandler() { 31 | String beanName = this.getHandlerName(); 32 | return (S) applicationContext.getBean(beanName); 33 | } 34 | 35 | protected String getHandlerName() { 36 | String fullHandlerName = this.request.getClass().getSimpleName() + "Handler"; 37 | return Character.toLowerCase(fullHandlerName.charAt(0)) + fullHandlerName.substring(1); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/processing/builder/CommandHandlerPipelineBuilder.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.processing.builder; 2 | 3 | import com.tomo.mcauthentication.application.configuration.CommandHandler; 4 | import com.tomo.mcauthentication.application.contracts.Command; 5 | import com.tomo.mcauthentication.infrastructure.processing.LoggingCommandHandlerDecorator; 6 | import com.tomo.mcauthentication.infrastructure.processing.PipelineBuilder; 7 | 8 | public class CommandHandlerPipelineBuilder extends AbstractPipelineBuilder { 9 | 10 | public CommandHandlerPipelineBuilder() {} 11 | 12 | @Override 13 | public CommandHandlerPipelineBuilder with(Command aRequest) { 14 | return (CommandHandlerPipelineBuilder) super.with(aRequest); 15 | } 16 | 17 | @Override 18 | public CommandHandler build() { 19 | return new LoggingCommandHandlerDecorator(handler); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/processing/builder/QueryHandlerPipelineBuilder.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.processing.builder; 2 | 3 | import com.tomo.mcauthentication.application.configuration.QueryHandler; 4 | import com.tomo.mcauthentication.application.contracts.Query; 5 | import com.tomo.mcauthentication.infrastructure.processing.LoggingQueryHandlerDecorator; 6 | import com.tomo.mcauthentication.infrastructure.processing.PipelineBuilder; 7 | 8 | public class QueryHandlerPipelineBuilder extends AbstractPipelineBuilder { 9 | 10 | public QueryHandlerPipelineBuilder() { 11 | } 12 | 13 | @Override 14 | public QueryHandlerPipelineBuilder with(Query aRequest) { 15 | return (QueryHandlerPipelineBuilder) super.with(aRequest); 16 | } 17 | 18 | @Override 19 | public QueryHandler build() { 20 | return new LoggingQueryHandlerDecorator(handler); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/service/MD5EncryptionService.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.service; 2 | 3 | import com.tomo.ddd.AssertionConcern; 4 | import com.tomo.mcauthentication.domain.EncryptionService; 5 | 6 | import org.springframework.beans.factory.annotation.Qualifier; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.math.BigInteger; 10 | import java.security.MessageDigest; 11 | 12 | @Service 13 | @Qualifier("MD5EncryptionService") 14 | public class MD5EncryptionService extends AssertionConcern implements EncryptionService { 15 | 16 | public MD5EncryptionService() { 17 | super(); 18 | } 19 | 20 | @Override 21 | public String encryptedValue(String aPlainTextValue) { 22 | this.assertArgumentNotEmpty( 23 | aPlainTextValue, 24 | "Plain text value to encrypt must be provided."); 25 | 26 | String encryptedValue = null; 27 | 28 | try { 29 | 30 | MessageDigest messageDigest = MessageDigest.getInstance("MD5"); 31 | 32 | messageDigest.update(aPlainTextValue.getBytes("UTF-8")); 33 | 34 | BigInteger bigInt = new BigInteger(1, messageDigest.digest()); 35 | 36 | encryptedValue = bigInt.toString(16); 37 | 38 | } catch (Exception e) { 39 | throw new IllegalStateException(e); 40 | } 41 | 42 | return encryptedValue; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/configuration/AppProperties.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.configuration; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | @ConfigurationProperties(prefix = "app") 9 | public class AppProperties { 10 | private final Auth auth = new Auth(); 11 | private final OAuth2 oauth2 = new OAuth2(); 12 | private final MessageProperties message = new MessageProperties(); 13 | private String baseUrl; 14 | private final GUIProperties gui = new GUIProperties(); 15 | 16 | public static class Auth { 17 | private String tokenSecret; 18 | private String sessionAuthTokenName; 19 | private long tokenExpirationMsec; 20 | 21 | public String getTokenSecret() { 22 | return tokenSecret; 23 | } 24 | 25 | public void setTokenSecret(String tokenSecret) { 26 | this.tokenSecret = tokenSecret; 27 | } 28 | 29 | public long getTokenExpirationMsec() { 30 | return tokenExpirationMsec; 31 | } 32 | 33 | public void setTokenExpirationMsec(long tokenExpirationMsec) { 34 | this.tokenExpirationMsec = tokenExpirationMsec; 35 | } 36 | 37 | public String getSessionAuthTokenName() { 38 | return sessionAuthTokenName; 39 | } 40 | 41 | public void setSessionAuthTokenName(String sessionAuthTokenName) { 42 | this.sessionAuthTokenName = sessionAuthTokenName; 43 | } 44 | } 45 | 46 | public static final class OAuth2 { 47 | private List authorizedRedirectUris = new ArrayList<>(); 48 | 49 | public List getAuthorizedRedirectUris() { 50 | return authorizedRedirectUris; 51 | } 52 | 53 | public OAuth2 authorizedRedirectUris(List authorizedRedirectUris) { 54 | this.authorizedRedirectUris = authorizedRedirectUris; 55 | return this; 56 | } 57 | } 58 | 59 | public Auth getAuth() { 60 | return auth; 61 | } 62 | 63 | public OAuth2 getOauth2() { 64 | return oauth2; 65 | } 66 | 67 | public MessageProperties getMessage() { 68 | return message; 69 | } 70 | 71 | public GUIProperties getGui() { 72 | return gui; 73 | } 74 | 75 | public String getBaseUrl() { 76 | return baseUrl; 77 | } 78 | 79 | public void setBaseUrl(String baseUrl) { 80 | this.baseUrl = baseUrl; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/configuration/GUIProperties.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.configuration; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | @NoArgsConstructor 10 | public class GUIProperties { 11 | String baseUrl; 12 | String recoveryRoute; 13 | String confirmationRoute; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/configuration/MessageProperties.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.configuration; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | @NoArgsConstructor 10 | public class MessageProperties { 11 | 12 | private Email email = new Email(); 13 | 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | public static class Email { 18 | MailGun mailGun = new MailGun(); 19 | String fakeEmail = "tomo.landeka02@gmail.com"; 20 | 21 | @Getter 22 | @Setter 23 | @NoArgsConstructor 24 | public static class MailGun { 25 | String domains; 26 | String apiUrl; 27 | String apiKey; 28 | From from; 29 | 30 | @Getter 31 | @Setter 32 | @NoArgsConstructor 33 | public static class From { 34 | String name; 35 | String email; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/configuration/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.configuration; 2 | 3 | import com.tomo.mcauthentication.infrastructure.springboot.security.OAuth2AuthenticationFailureHandler; 4 | import com.tomo.mcauthentication.infrastructure.springboot.security.OAuth2AuthenticationSuccessHandler; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 11 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 12 | import org.springframework.security.config.http.SessionCreationPolicy; 13 | 14 | @Configuration 15 | @EnableWebSecurity 16 | @EnableGlobalMethodSecurity( 17 | securedEnabled = true, 18 | jsr250Enabled = true, 19 | prePostEnabled = true 20 | ) 21 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 22 | 23 | @Autowired 24 | private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler; 25 | 26 | @Autowired 27 | private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler; 28 | 29 | @Override 30 | protected void configure(HttpSecurity http) throws Exception { 31 | http.csrf().disable() 32 | .authorizeRequests() 33 | .anyRequest().permitAll() 34 | .and() 35 | .sessionManagement() 36 | .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) 37 | .and() 38 | .oauth2Login() 39 | .successHandler(oAuth2AuthenticationSuccessHandler) 40 | .failureHandler(oAuth2AuthenticationFailureHandler); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/configuration/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.configuration; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | import springfox.documentation.builders.PathSelectors; 7 | import springfox.documentation.builders.RequestHandlerSelectors; 8 | import springfox.documentation.spi.DocumentationType; 9 | import springfox.documentation.spring.web.plugins.Docket; 10 | 11 | @Configuration 12 | public class SwaggerConfig { 13 | @Bean 14 | public Docket api() { 15 | return new Docket(DocumentationType.SWAGGER_2) 16 | .select() 17 | .apis(RequestHandlerSelectors.any()) 18 | .paths(PathSelectors.any()) 19 | .build(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/configuration/SwaggerUiWebMvcConfigurer.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.configuration; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.util.StringUtils; 6 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 7 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 8 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10 | 11 | @Component 12 | public class SwaggerUiWebMvcConfigurer implements WebMvcConfigurer { 13 | private final String baseUrl; 14 | 15 | public SwaggerUiWebMvcConfigurer(@Value("${app.base-url:}") String baseUrl) { 16 | this.baseUrl = baseUrl; 17 | } 18 | 19 | @Override 20 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 21 | String baseUrl = StringUtils.trimTrailingCharacter(this.baseUrl, '/'); 22 | registry. 23 | addResourceHandler(baseUrl + "/swagger-ui/**") 24 | .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/") 25 | .resourceChain(false); 26 | } 27 | 28 | @Override 29 | public void addViewControllers(ViewControllerRegistry registry) { 30 | registry.addViewController(baseUrl + "/swagger-ui/") 31 | .setViewName("forward:" + baseUrl + "/swagger-ui/index.html"); 32 | } 33 | 34 | @Override 35 | public void addCorsMappings(CorsRegistry registry) { 36 | registry 37 | .addMapping("/api/pet") 38 | .allowedOrigins("http://editor.swagger.io"); 39 | registry 40 | .addMapping("/v2/api-docs.*") 41 | .allowedOrigins("http://editor.swagger.io"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/controller/AbstractController.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.controller; 2 | 3 | import com.tomo.mcauthentication.application.contracts.Command; 4 | import com.tomo.mcauthentication.application.contracts.McAuthenticationModule; 5 | import com.tomo.mcauthentication.application.contracts.Query; 6 | import com.tomo.mcauthentication.application.contracts.Request; 7 | import com.tomo.mcauthentication.application.contracts.Response; 8 | import com.tomo.mcauthentication.application.contracts.security.Authenticate; 9 | import com.tomo.mcauthentication.domain.session.TokenProvider; 10 | import com.tomo.mcauthentication.infrastructure.springboot.configuration.AppProperties; 11 | import com.tomo.mcauthentication.infrastructure.util.CookieUtils; 12 | 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.util.StringUtils; 15 | 16 | import javax.servlet.http.HttpServletRequest; 17 | 18 | public abstract class AbstractController { 19 | 20 | @Autowired 21 | protected McAuthenticationModule authenticationModule; 22 | 23 | @Autowired 24 | protected AppProperties properties; 25 | 26 | @Autowired 27 | protected HttpServletRequest request; 28 | 29 | @Autowired 30 | protected TokenProvider tokenProvider; 31 | 32 | protected Response executeCommand(Command command) { 33 | this.setAuthToken(command); 34 | return authenticationModule.executeCommand(command); 35 | } 36 | 37 | protected T executeCommand(Command command, Class tclass) { 38 | this.setAuthToken(command); 39 | return tclass.cast(authenticationModule.executeCommand(command)); 40 | } 41 | 42 | protected T executeQuery(Query query, Class tclass) { 43 | this.setAuthToken(query); 44 | return tclass.cast(authenticationModule.executeQuery(query)); 45 | } 46 | 47 | private void setAuthToken(Request request) { 48 | if (request instanceof Authenticate) { 49 | String jwt = getJwtFromRequest(); 50 | if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { 51 | ((Authenticate) request).setAuthToken(jwt); 52 | } 53 | } 54 | } 55 | 56 | private String getJwtFromRequest() { 57 | return CookieUtils.getCookie(request, properties.getAuth().getSessionAuthTokenName()) 58 | .map(cookie -> CookieUtils.deserialize(cookie, String.class)) 59 | // .filter(cookie -> StringUtils.hasText(cookie) && cookie.startsWith("Bearer ")) 60 | // .map(cookie -> cookie.substring(7)) 61 | .orElse(null); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/controller/RegistrationController.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.controller; 2 | 3 | import com.tomo.mcauthentication.application.recovery.command.CreatePasswordRecoveryCodeCommand; 4 | import com.tomo.mcauthentication.application.recovery.command.UpdatePasswordWithRecoveryCodeCommand; 5 | import com.tomo.mcauthentication.application.registration.command.ConfirmUserRegistrationCommand; 6 | import com.tomo.mcauthentication.application.registration.command.RegisterNewUserCommand; 7 | import com.tomo.mcauthentication.infrastructure.springboot.controller.RestApiRoutes.RegistrationRoutes; 8 | 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.validation.annotation.Validated; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestMethod; 14 | import org.springframework.web.bind.annotation.RequestParam; 15 | import org.springframework.web.bind.annotation.ResponseStatus; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | @RestController 19 | @RequestMapping(path = "/") 20 | public class RegistrationController extends AbstractController { 21 | 22 | @RequestMapping(method = RequestMethod.POST, path = RegistrationRoutes.FORM_REGISTRATION) 23 | @ResponseStatus(HttpStatus.CREATED) 24 | public void formRegister(@RequestBody @Validated RegisterNewUserCommand command){ 25 | this.executeCommand(command); 26 | } 27 | 28 | @RequestMapping(method = RequestMethod.POST, path = RegistrationRoutes.CONFIRM_REGISTRATION) 29 | @ResponseStatus(HttpStatus.OK) 30 | public void formRegisterConfirmation(@RequestParam String confirmationCode){ 31 | this.executeCommand(new ConfirmUserRegistrationCommand(confirmationCode)); 32 | } 33 | 34 | @RequestMapping(method = RequestMethod.PATCH, path = RegistrationRoutes.CREATE_PASSWORD_RECOVERY_CODE) 35 | @ResponseStatus(HttpStatus.OK) 36 | public void formRegisterRecovery(@RequestBody @Validated CreatePasswordRecoveryCodeCommand command){ 37 | this.executeCommand(command); 38 | } 39 | 40 | @RequestMapping(method = RequestMethod.PATCH, path = RegistrationRoutes.PASSWORD_RESET) 41 | @ResponseStatus(HttpStatus.OK) 42 | public void passwordReset(@RequestBody @Validated UpdatePasswordWithRecoveryCodeCommand command) { 43 | this.executeCommand(command); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/controller/RestApiRoutes.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.controller; 2 | 3 | public class RestApiRoutes { 4 | public static final String REST = "/rest"; 5 | public static final String PUBLIC = REST + "/public"; 6 | public static final String PRIVATE = REST + "/private"; 7 | 8 | public static class RegistrationRoutes { 9 | public static final String FORM_REGISTRATION = PUBLIC + "/register/form"; 10 | public static final String CONFIRM_REGISTRATION = PUBLIC + "/register/confirm/"; 11 | public static final String CREATE_PASSWORD_RECOVERY_CODE = PUBLIC + "/register/password/recovery-code"; 12 | public static final String PASSWORD_RESET = PUBLIC + "/register/password/reset"; 13 | } 14 | 15 | public static class AuthRoutes { 16 | public static final String FORM_LOGIN = PUBLIC + "/login/form"; 17 | public static final String FACEBOOK_LOGIN = PUBLIC + "/login/facebook"; 18 | public static final String GOOGLE_LOGIN = PUBLIC + "/login/google"; 19 | public static final String LOGOUT = PRIVATE + "/logout"; 20 | } 21 | 22 | public static class User { 23 | public static final String USER = PRIVATE + "/user"; 24 | public static final String USER_DETAILS = USER + "/{userId}"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.controller; 2 | 3 | import com.tomo.mcauthentication.application.users.command.ChangeUserDetailsCommand; 4 | import com.tomo.mcauthentication.application.users.dto.BaseUserDto; 5 | import com.tomo.mcauthentication.application.users.query.GetUserQuery; 6 | import com.tomo.mcauthentication.infrastructure.springboot.controller.RestApiRoutes.User; 7 | 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.validation.annotation.Validated; 11 | import org.springframework.web.bind.annotation.PathVariable; 12 | import org.springframework.web.bind.annotation.RequestBody; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RequestMethod; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | import java.util.UUID; 18 | 19 | @RestController 20 | @RequestMapping(path = "/") 21 | public class UserController extends AbstractController { 22 | 23 | @RequestMapping(method = RequestMethod.GET, path = User.USER_DETAILS) 24 | public ResponseEntity user(@PathVariable(value = "userId") String userId){ 25 | BaseUserDto dto = this.executeQuery(new GetUserQuery(userId), BaseUserDto.class); 26 | 27 | return ResponseEntity.ok(dto); 28 | } 29 | 30 | @RequestMapping(method = RequestMethod.PATCH, path = User.USER_DETAILS) 31 | public ResponseEntity user( 32 | @PathVariable(value = "userId") UUID userId, 33 | @RequestBody @Validated ChangeUserDetailsCommand command){ 34 | command.setUserId(userId); 35 | this.executeCommand(command); 36 | return new ResponseEntity(HttpStatus.OK); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/security/CurrentUser.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.security; 2 | 3 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | @Target({ElementType.PARAMETER, ElementType.TYPE}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Documented 14 | @AuthenticationPrincipal 15 | public @interface CurrentUser { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/security/OAuth2AuthenticationFailureHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.security; 2 | 3 | import org.springframework.security.core.AuthenticationException; 4 | import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; 5 | import org.springframework.stereotype.Component; 6 | 7 | import javax.servlet.ServletException; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | 12 | @Component 13 | public class OAuth2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { 14 | 15 | @Override 16 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { 17 | int a = 1; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/security/OAuth2AuthenticationSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.security; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.security.core.Authentication; 5 | import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.util.UriComponentsBuilder; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.Cookie; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | import java.net.URI; 15 | import java.util.Optional; 16 | 17 | @Component 18 | public class OAuth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { 19 | 20 | @Override 21 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) 22 | throws IOException, ServletException { 23 | String targetUrl = determineTargetUrl(request, response, authentication); 24 | 25 | if (response.isCommitted()) { 26 | logger.debug("Response has already been committed. Unable to redirect to " + targetUrl); 27 | return; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/security/UserAuthPrincipal.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.security; 2 | 3 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 4 | import com.tomo.mcauthentication.domain.users.User; 5 | 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.userdetails.UserDetails; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Collection; 11 | import java.util.UUID; 12 | 13 | public class UserAuthPrincipal implements UserDetails { 14 | 15 | private SessionDto session; 16 | 17 | private final Collection authorities; 18 | 19 | private boolean enabled = true; 20 | 21 | public UserAuthPrincipal(SessionDto session) { 22 | this.session = session; 23 | this.authorities = new ArrayList<>(); 24 | } 25 | 26 | public SessionDto getSession() { 27 | return session; 28 | } 29 | 30 | @Override 31 | public Collection getAuthorities() { 32 | return new ArrayList<>(); 33 | } 34 | 35 | @Override 36 | public String getPassword() { 37 | return null; 38 | } 39 | 40 | @Override 41 | public String getUsername() { 42 | return session.getUserId(); 43 | } 44 | 45 | @Override 46 | public boolean isAccountNonExpired() { 47 | return this.enabled; 48 | } 49 | 50 | @Override 51 | public boolean isAccountNonLocked() { 52 | return this.enabled; 53 | } 54 | 55 | @Override 56 | public boolean isCredentialsNonExpired() { 57 | return this.enabled; 58 | } 59 | 60 | @Override 61 | public boolean isEnabled() { 62 | return this.enabled; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/springboot/security/UserAuthToken.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.springboot.security; 2 | 3 | import com.tomo.mcauthentication.domain.users.User; 4 | 5 | import org.springframework.security.authentication.AbstractAuthenticationToken; 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 8 | 9 | import java.util.Collection; 10 | 11 | public class UserAuthToken extends AbstractAuthenticationToken { 12 | 13 | private UserAuthPrincipal userPrincipal; 14 | 15 | public UserAuthToken(UserAuthPrincipal userPrincipal) { 16 | super(userPrincipal.getAuthorities()); 17 | super.setAuthenticated(true); 18 | this.userPrincipal = userPrincipal; 19 | } 20 | 21 | public UserAuthToken(String authToken, Collection authorities) { 22 | super(authorities); 23 | this.setAuthenticated(true); 24 | } 25 | 26 | @Override 27 | public Object getCredentials() { 28 | return null; 29 | } 30 | 31 | @Override 32 | public Object getPrincipal() { 33 | return userPrincipal; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/tomo/mcauthentication/infrastructure/util/CookieUtils.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.infrastructure.util; 2 | 3 | import org.springframework.util.SerializationUtils; 4 | 5 | import javax.servlet.http.Cookie; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | import java.util.Base64; 9 | import java.util.Optional; 10 | 11 | public class CookieUtils { 12 | 13 | public static Optional getCookie(HttpServletRequest request, String name) { 14 | Cookie[] cookies = request.getCookies(); 15 | 16 | if (cookies != null && cookies.length > 0) { 17 | for (Cookie cookie : cookies) { 18 | if (cookie.getName().equals(name)) { 19 | return Optional.of(cookie); 20 | } 21 | } 22 | } 23 | 24 | return Optional.empty(); 25 | } 26 | 27 | public static void addCookie(HttpServletResponse response, String name, String value, int maxAge) { 28 | Cookie cookie = new Cookie(name, value); 29 | cookie.setPath("/"); 30 | cookie.setMaxAge(5000); 31 | response.addCookie(cookie); 32 | } 33 | 34 | public static void updateCookie(HttpServletRequest request, HttpServletResponse response, String name, String value, int maxAge) { 35 | Cookie[] cookies = request.getCookies(); 36 | if (cookies != null && cookies.length > 0) { 37 | for (Cookie cookie: cookies) { 38 | if (cookie.getName().equals(name)) { 39 | cookie.setValue(value); 40 | cookie.setPath("/"); 41 | cookie.setMaxAge(maxAge); 42 | response.addCookie(cookie); 43 | } 44 | } 45 | } 46 | } 47 | 48 | public static void deleteCookie(HttpServletRequest request, HttpServletResponse response, String name) { 49 | Cookie[] cookies = request.getCookies(); 50 | if (cookies != null && cookies.length > 0) { 51 | for (Cookie cookie: cookies) { 52 | if (cookie.getName().equals(name)) { 53 | cookie.setValue(""); 54 | cookie.setPath("/"); 55 | cookie.setMaxAge(0); 56 | response.addCookie(cookie); 57 | } 58 | } 59 | } 60 | } 61 | 62 | public static String serialize(Object object) { 63 | return Base64.getUrlEncoder() 64 | .encodeToString(SerializationUtils.serialize(object)); 65 | } 66 | 67 | public static T deserialize(Cookie cookie, Class cls) { 68 | return cls.cast(SerializationUtils.deserialize( 69 | Base64.getUrlDecoder().decode(cookie.getValue()))); 70 | } 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | debug: true 4 | 5 | spring: 6 | datasource: 7 | url: jdbc:postgresql://localhost:5432/mc_authentication 8 | username: mcuser 9 | password: mcuser 10 | driver-class-name: org.postgresql.Driver 11 | 12 | jpa: 13 | show-sql: true 14 | hibernate: 15 | ddl-auto: none 16 | naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy 17 | properties: 18 | hibernate: 19 | dialect: org.hibernate.dialect.PostgreSQL9Dialect 20 | 21 | flyway: 22 | enabled: true 23 | baselineOnMigrate: true 24 | schemas: public 25 | 26 | security: 27 | oauth2: 28 | client: 29 | registration: 30 | google: 31 | clientId: your-client-id.apps.googleusercontent.com 32 | clientSecret: your-client-secret 33 | scope: 34 | - email 35 | - profile 36 | facebook: 37 | clientId: your-client-id 38 | clientSecret: your-client-secret 39 | scope: 40 | - email 41 | - public_profile 42 | provider: 43 | facebook: 44 | authorizationUri: https://www.facebook.com/v3.0/dialog/oauth 45 | tokenUri: https://graph.facebook.com/v3.0/oauth/access_token 46 | userInfoUri: https://graph.facebook.com/v3.0/me?fields=id,first_name,middle_name,last_name,name,email,verified,is_verified,picture.width(250).height(250) 47 | app: 48 | base-url: http://localhost:8080 49 | auth: 50 | tokenSecret: 04ca023b39512e46d0c2cf4b48d5aac61d34302994c87ed4eff225dcf3b0a218739f3897051a057f9b846a69ea2927a587044164b7bae5e1306219d50b588cb1 51 | tokenExpirationMsec: 864000000 52 | sessionAuthTokenName: "dei-www" 53 | cors: 54 | allowedOrigins: http://localhost:3000,http://localhost:8080 55 | 56 | message: 57 | email: 58 | mailgun: 59 | domains: "[your-sandbox].mailgun.org" 60 | api-url: "https://api.mailgun.net/v3/" 61 | api-key: "[mailgun-api-key]" 62 | from: 63 | name: "mc team" 64 | email: "tomo.landeka02@gmail.com" 65 | gui: 66 | base-url: "localhost:3000" 67 | recovery-route: "${app.gui.base-url}/reset-password/?recoveryCode=" 68 | confirmation-route: "${app.gui.base-url}/register/confirm/?confirmationCode=" -------------------------------------------------------------------------------- /src/main/resources/db/migration/V2022_02_02_1124__initial_structure.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE mcuser ( 2 | id UUID PRIMARY KEY NOT NULL, 3 | first_name VARCHAR(255), 4 | last_name VARCHAR(255), 5 | provider VARCHAR(50) NOT NULL, 6 | email VARCHAR(255) NOT NULL 7 | CONSTRAINT mcuser_email_unique unique, 8 | concurrency_version BIGINT, 9 | created TIMESTAMP NOT NULL DEFAULT Now(), 10 | modified TIMESTAMP 11 | ); 12 | 13 | CREATE TABLE user_registration ( 14 | id BIGSERIAL PRIMARY KEY, 15 | first_name VARCHAR(255), 16 | last_name VARCHAR(255), 17 | email VARCHAR(255) NOT NULL, 18 | password VARCHAR(255) NOT NULL, 19 | confirmation_code VARCHAR(255) NOT NULL, 20 | status VARCHAR(255) NOT NULL, 21 | register_date TIMESTAMP, 22 | recovery_code VARCHAR(255), 23 | recovery_code_expiration_date TIMESTAMP, 24 | user_id UUID 25 | CONSTRAINT user_registration_mcuser_id_fk REFERENCES mcuser, 26 | concurrency_version BIGINT, 27 | created TIMESTAMP DEFAULT now() NOT NULL, 28 | modified TIMESTAMP 29 | ); 30 | 31 | create table session ( 32 | id UUID PRIMARY KEY, 33 | user_id UUID NOT NULL CONSTRAINT session_mcuser_id_fk REFERENCES mcuser, 34 | access_token TEXT NOT NULL, 35 | expiration_date TIMESTAMP, 36 | token_type TEXT NOT NULL, 37 | refresh_token TEXT, 38 | user_agent TEXT, 39 | ip_address VARCHAR(45), 40 | last_activity TIMESTAMP, 41 | created TIMESTAMP DEFAULT now() NOT NULL, 42 | modified TIMESTAMP 43 | ); 44 | 45 | CREATE UNIQUE INDEX user_registration_user_id_uindex ON user_registration(user_id); 46 | 47 | CREATE TABLE stored_event ( 48 | event_id BIGSERIAL PRIMARY KEY, 49 | event_body TEXT NOT NULL, 50 | occurred_on TIMESTAMP NOT NULL, 51 | type_name VARCHAR (200) NOT NULL 52 | ); 53 | -------------------------------------------------------------------------------- /src/main/resources/repo/org/tomo/ddd_common/1.0.0/ddd_common-1.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tlandeka/authentication-microservice-with-domain-driven-design/a7cfd82824d91d90e1f07a613cdeae1bd59f91e0/src/main/resources/repo/org/tomo/ddd_common/1.0.0/ddd_common-1.0.0.jar -------------------------------------------------------------------------------- /src/main/resources/repo/org/tomo/ddd_common/1.0.0/ddd_common-1.0.0.jar.md5: -------------------------------------------------------------------------------- 1 | d6f732badc879e635745ef1ee13673d3 -------------------------------------------------------------------------------- /src/main/resources/repo/org/tomo/ddd_common/1.0.0/ddd_common-1.0.0.jar.sha1: -------------------------------------------------------------------------------- 1 | 49221e5069bd616ba23339076cad6478d3762710 -------------------------------------------------------------------------------- /src/main/resources/repo/org/tomo/ddd_common/1.0.0/ddd_common-1.0.0.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | org.tomo 6 | ddd_common 7 | 1.0.0 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/repo/org/tomo/ddd_common/1.0.0/ddd_common-1.0.0.pom.md5: -------------------------------------------------------------------------------- 1 | 5238d5a53bcbfbe70a6cb87ed493d6f3 -------------------------------------------------------------------------------- /src/main/resources/repo/org/tomo/ddd_common/1.0.0/ddd_common-1.0.0.pom.sha1: -------------------------------------------------------------------------------- 1 | 423681301f4b73b38060c3c069f0141c0b54c660 -------------------------------------------------------------------------------- /src/main/resources/repo/org/tomo/ddd_common/maven-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.tomo 4 | ddd_common 5 | 6 | 1.0.0 7 | 8 | 1.0.0 9 | 10 | 20221113150911 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/resources/repo/org/tomo/ddd_common/maven-metadata.xml.md5: -------------------------------------------------------------------------------- 1 | 2dfb0c4eb83fb0e21037e00e71ab51cb -------------------------------------------------------------------------------- /src/main/resources/repo/org/tomo/ddd_common/maven-metadata.xml.sha1: -------------------------------------------------------------------------------- 1 | b984353efb5206ed31336cb8a1508c6453122adb -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/BaseIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | import org.springframework.test.context.junit4.SpringRunner; 6 | 7 | @RunWith(SpringRunner.class) 8 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 9 | public abstract class BaseIntegrationTest { } 10 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/authentication/EmailLoginCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.authentication; 2 | 3 | import com.tomo.ddd.domain.BusinessRuleValidationException; 4 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 5 | import org.junit.Test; 6 | 7 | import javax.transaction.Transactional; 8 | 9 | import static org.junit.Assert.assertNotNull; 10 | import static org.junit.Assert.assertThrows; 11 | 12 | public class EmailLoginCommandHandlerTest extends AbstractApplicationServiceTest { 13 | 14 | @Test 15 | @Transactional 16 | public void testUserFormLogin() { 17 | assertNotNull(formLogin()); 18 | } 19 | 20 | @Test 21 | @Transactional 22 | public void testNewFormUserFailedWhenGoogleUserExists() { 23 | createGoogleUser(); 24 | assertThrows(BusinessRuleValidationException.class, this::createFormUser); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/authentication/FacebookLoginCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.authentication; 2 | 3 | import com.tomo.ddd.domain.BusinessRuleValidationException; 4 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 5 | import org.junit.Test; 6 | 7 | import javax.transaction.Transactional; 8 | 9 | import static org.junit.Assert.assertNotNull; 10 | import static org.junit.Assert.assertThrows; 11 | 12 | public class FacebookLoginCommandHandlerTest extends AbstractApplicationServiceTest { 13 | 14 | @Test 15 | @Transactional 16 | public void testNewFacebookUserCreated() { 17 | assertNotNull(createFacbookUser()); 18 | } 19 | 20 | @Test 21 | @Transactional 22 | public void testNewFacebookUserFailedWhenGoogleUserExists() { 23 | createGoogleUser(); 24 | assertThrows(BusinessRuleValidationException.class, this::createFacbookUser); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/authentication/GoogleLoginCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.authentication; 2 | 3 | import com.tomo.ddd.domain.BusinessRuleValidationException; 4 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 5 | import org.junit.Test; 6 | 7 | import javax.transaction.Transactional; 8 | 9 | import static org.junit.Assert.assertNotNull; 10 | import static org.junit.Assert.assertThrows; 11 | 12 | public class GoogleLoginCommandHandlerTest extends AbstractApplicationServiceTest { 13 | 14 | @Test 15 | @Transactional 16 | public void testNewGoogleUserCreated() { 17 | assertNotNull(createGoogleUser()); 18 | } 19 | 20 | @Test 21 | @Transactional 22 | public void testNewGoogleUserFailedWhenFacebookUserExists() { 23 | createFacbookUser(); 24 | assertThrows(BusinessRuleValidationException.class, this::createGoogleUser); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/authentication/LogoutCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.authentication; 2 | 3 | import com.tomo.ddd.domain.BusinessRuleValidationException; 4 | import com.tomo.mcauthentication.application.authentication.LogoutCommandHandler; 5 | import com.tomo.mcauthentication.application.authentication.command.LogoutCommand; 6 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 7 | import com.tomo.mcauthentication.domain.session.SessionAuthenticationService; 8 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 9 | import org.junit.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | import javax.transaction.Transactional; 13 | 14 | import static org.junit.Assert.assertThrows; 15 | 16 | public class LogoutCommandHandlerTest extends AbstractApplicationServiceTest { 17 | 18 | @Autowired 19 | LogoutCommandHandler logoutCommandHandler; 20 | 21 | @Autowired 22 | SessionAuthenticationService sessionAuthenticationService; 23 | 24 | @Test 25 | @Transactional 26 | public void testLogout() { 27 | SessionDto sessionDto = formLogin(); 28 | logoutCommandHandler.handle(new LogoutCommand(sessionDto.getAccessToken())); 29 | assertThrows(BusinessRuleValidationException.class, () -> sessionAuthenticationService.authenticate(sessionDto.getAccessToken())); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/authentication/SessionAuthenticationCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.authentication; 2 | 3 | import com.tomo.mcauthentication.application.authentication.SessionAuthenticationCommandHandler; 4 | import com.tomo.mcauthentication.application.authentication.command.SessionAuthenticationCommand; 5 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 6 | import com.tomo.mcauthentication.domain.session.SessionAuthenticationService; 7 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 8 | import org.junit.Test; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | 11 | import javax.transaction.Transactional; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | 15 | public class SessionAuthenticationCommandHandlerTest extends AbstractApplicationServiceTest { 16 | 17 | @Autowired 18 | SessionAuthenticationCommandHandler commandHandler; 19 | 20 | @Autowired 21 | SessionAuthenticationService sessionAuthenticationService; 22 | 23 | @Test 24 | @Transactional 25 | public void testAuthenticateSession() { 26 | SessionDto initialSessionDto = formLogin(); 27 | SessionDto sessionDto = commandHandler.handle(new SessionAuthenticationCommand(initialSessionDto.getAccessToken())); 28 | assertEquals(initialSessionDto.getAccessToken(), sessionDto.getAccessToken()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/recovery/CreatePasswordRecoveryCodeCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.recovery; 2 | 3 | import com.tomo.mcauthentication.application.authentication.dto.RecoveryPasswordDto; 4 | import com.tomo.mcauthentication.application.recovery.CreatePasswordRecoveryCodeCommandHandler; 5 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 6 | import com.tomo.mcauthentication.testdata.CommandObjectMother; 7 | import org.junit.Test; 8 | import org.mockito.Mockito; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | 11 | import javax.transaction.Transactional; 12 | 13 | import static org.junit.Assert.assertNotNull; 14 | import static org.mockito.ArgumentMatchers.any; 15 | import static org.mockito.Mockito.verify; 16 | 17 | public class CreatePasswordRecoveryCodeCommandHandlerTest extends AbstractApplicationServiceTest { 18 | 19 | @Autowired 20 | CreatePasswordRecoveryCodeCommandHandler commandHandler; 21 | 22 | @Test 23 | @Transactional 24 | public void testRecoveryCodeCreated() { 25 | formLogin(); 26 | RecoveryPasswordDto recoveryPasswordDto = commandHandler.handle(CommandObjectMother.createPasswordRecoveryCodeCommand()); 27 | assertNotNull(recoveryPasswordDto); 28 | verify(this.sendPasswordRecoveryEmailCommandHandler, Mockito.times(1)).handle(any()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/recovery/GetUserRegistrationWithRecoveryCodeQueryHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.recovery; 2 | 3 | import com.tomo.mcauthentication.application.authentication.dto.RecoveryPasswordDto; 4 | import com.tomo.mcauthentication.application.recovery.CreatePasswordRecoveryCodeCommandHandler; 5 | import com.tomo.mcauthentication.application.recovery.GetUserRegistrationWithRecoveryCodeQueryHandler; 6 | import com.tomo.mcauthentication.application.recovery.dto.GetUserRegistrationWithRecoveryCodeQuery; 7 | import com.tomo.mcauthentication.application.registration.dto.UserRegistrationDto; 8 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 9 | import com.tomo.mcauthentication.testdata.CommandObjectMother; 10 | import org.junit.Test; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | 13 | import javax.transaction.Transactional; 14 | 15 | import static org.junit.Assert.assertNotNull; 16 | 17 | public class GetUserRegistrationWithRecoveryCodeQueryHandlerTest extends AbstractApplicationServiceTest { 18 | 19 | @Autowired 20 | GetUserRegistrationWithRecoveryCodeQueryHandler queryHandler; 21 | 22 | @Autowired 23 | CreatePasswordRecoveryCodeCommandHandler commandHandler; 24 | 25 | @Test 26 | @Transactional 27 | public void testGetUserRegistrationWithRecoveryCode() { 28 | formLogin(); 29 | RecoveryPasswordDto recoveryPasswordDto = commandHandler.handle(CommandObjectMother.createPasswordRecoveryCodeCommand()); 30 | UserRegistrationDto userRegistrationDto = queryHandler.handle(new GetUserRegistrationWithRecoveryCodeQuery(recoveryPasswordDto.getRecoveryCode())); 31 | assertNotNull(userRegistrationDto.getEmail()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/recovery/UpdatePasswordWithRecoveryCodeCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.recovery; 2 | 3 | import com.tomo.mcauthentication.application.authentication.command.EmailLoginCommand; 4 | import com.tomo.mcauthentication.application.authentication.dto.RecoveryPasswordDto; 5 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 6 | import com.tomo.mcauthentication.application.contracts.Voidy; 7 | import com.tomo.mcauthentication.application.recovery.CreatePasswordRecoveryCodeCommandHandler; 8 | import com.tomo.mcauthentication.application.recovery.UpdatePasswordWithRecoveryCodeCommandHandler; 9 | import com.tomo.mcauthentication.application.recovery.command.UpdatePasswordWithRecoveryCodeCommand; 10 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 11 | import com.tomo.mcauthentication.testdata.CommandObjectMother; 12 | import com.tomo.mcauthentication.testdata.StaticFields; 13 | import org.junit.Test; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | 16 | import javax.transaction.Transactional; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | 20 | public class UpdatePasswordWithRecoveryCodeCommandHandlerTest extends AbstractApplicationServiceTest { 21 | 22 | @Autowired 23 | CreatePasswordRecoveryCodeCommandHandler createPasswordRecoveryCodeCommandHandler; 24 | 25 | @Autowired 26 | UpdatePasswordWithRecoveryCodeCommandHandler commandHandler; 27 | 28 | @Test 29 | @Transactional 30 | public void testUpdatePasswordWithRecoveryCode() { 31 | formLogin(); 32 | RecoveryPasswordDto recoveryPasswordDto = createPasswordRecoveryCodeCommandHandler.handle(CommandObjectMother.createPasswordRecoveryCodeCommand()); 33 | assertEquals(commandHandler.handle(new UpdatePasswordWithRecoveryCodeCommand( 34 | StaticFields.NEW_PASS, 35 | StaticFields.NEW_PASS, 36 | recoveryPasswordDto.getRecoveryCode())).getClass(), 37 | Voidy.class); 38 | 39 | assertEquals( 40 | emailLoginCommandHandler.handle(new EmailLoginCommand(StaticFields.USER_EMAIL, StaticFields.NEW_PASS)).getClass(), 41 | SessionDto.class 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/registration/ChangePasswordCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.registration; 2 | 3 | import com.tomo.ddd.domain.BusinessRuleValidationException; 4 | import com.tomo.mcauthentication.application.authentication.command.EmailLoginCommand; 5 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 6 | import com.tomo.mcauthentication.application.contracts.Voidy; 7 | import com.tomo.mcauthentication.application.registration.ChangePasswordCommandHandler; 8 | import com.tomo.mcauthentication.application.registration.command.ChangePasswordCommand; 9 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 10 | import com.tomo.mcauthentication.testdata.StaticFields; 11 | import org.junit.Test; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | 14 | import javax.transaction.Transactional; 15 | 16 | import static org.junit.Assert.assertEquals; 17 | import static org.junit.Assert.assertThrows; 18 | 19 | public class ChangePasswordCommandHandlerTest extends AbstractApplicationServiceTest { 20 | 21 | @Autowired 22 | ChangePasswordCommandHandler commandHandler; 23 | 24 | @Test 25 | @Transactional 26 | public void testChangePassword() { 27 | SessionDto sessionDto = formLogin(); 28 | 29 | assertEquals(commandHandler.handle(new ChangePasswordCommand( 30 | sessionDto.getAccessToken(), 31 | StaticFields.PASSWORD, 32 | StaticFields.NEW_PASS, 33 | StaticFields.NEW_PASS)).getClass(), 34 | Voidy.class); 35 | 36 | 37 | assertThrows(BusinessRuleValidationException.class, () -> emailLoginCommandHandler.handle(new EmailLoginCommand(StaticFields.USER_EMAIL, StaticFields.PASSWORD))); 38 | 39 | assertEquals( 40 | emailLoginCommandHandler.handle(new EmailLoginCommand(StaticFields.USER_EMAIL, StaticFields.NEW_PASS)).getClass(), 41 | SessionDto.class 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/registration/ConfirmUserRegistrationCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.registration; 2 | 3 | import com.tomo.mcauthentication.domain.users.User; 4 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 5 | import org.junit.Test; 6 | 7 | import javax.transaction.Transactional; 8 | 9 | import static org.junit.Assert.assertNotNull; 10 | 11 | public class ConfirmUserRegistrationCommandHandlerTest extends AbstractApplicationServiceTest { 12 | 13 | @Test 14 | @Transactional 15 | public void testConfirmUserRegistration() { 16 | User user = createFormUser(); 17 | assertNotNull(user); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/registration/RegisterNewUserCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.registration; 2 | 3 | import com.tomo.mcauthentication.application.registration.ConfirmUserRegistrationCommandHandler; 4 | import com.tomo.mcauthentication.application.registration.NewUserRegisteredEventHandler; 5 | import com.tomo.mcauthentication.application.registration.RegisterNewUserCommandHandler; 6 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 7 | import com.tomo.mcauthentication.domain.registration.UserRegistrationRepository; 8 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 9 | import org.junit.Test; 10 | import org.mockito.Mockito; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | 13 | import javax.transaction.Transactional; 14 | 15 | import static org.junit.Assert.assertNotNull; 16 | import static org.junit.Assert.assertThrows; 17 | import static org.mockito.ArgumentMatchers.any; 18 | import static org.mockito.Mockito.verify; 19 | 20 | public class RegisterNewUserCommandHandlerTest extends AbstractApplicationServiceTest { 21 | 22 | @Autowired 23 | RegisterNewUserCommandHandler commandHandler; 24 | 25 | @Autowired 26 | ConfirmUserRegistrationCommandHandler confirmUserRegistrationCommandHandler; 27 | 28 | @Autowired 29 | UserRegistrationRepository userRegistrationRepository; 30 | 31 | @Autowired 32 | NewUserRegisteredEventHandler newUserRegisteredEventHandler; 33 | 34 | @Test 35 | @Transactional 36 | public void testNewUserRegistrationCreated() { 37 | UserRegistration userRegistration = createUserRegistration(); 38 | assertNotNull(userRegistration); 39 | verify(this.sendRegistrationConfirmationEmailCommandHandler, Mockito.times(1)).handle(any()); 40 | } 41 | 42 | @Test 43 | @Transactional 44 | public void testNewUserRegistrationFailedWhenUserExists() { 45 | createFormUser(); 46 | 47 | assertThrows(RuntimeException.class, () -> { 48 | createUserRegistration(); 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/users/ChangeUserDetailsCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.users; 2 | 3 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 4 | import com.tomo.mcauthentication.application.users.ChangeUserDetailsCommandHandler; 5 | import com.tomo.mcauthentication.application.users.command.ChangeUserDetailsCommand; 6 | import com.tomo.mcauthentication.domain.users.User; 7 | import com.tomo.mcauthentication.domain.users.UserRepository; 8 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 9 | import com.tomo.mcauthentication.testdata.CommandObjectMother; 10 | import org.junit.Test; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | 13 | import javax.transaction.Transactional; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | 17 | public class ChangeUserDetailsCommandHandlerTest extends AbstractApplicationServiceTest { 18 | 19 | @Autowired 20 | ChangeUserDetailsCommandHandler commandHandler; 21 | 22 | @Autowired 23 | UserRepository userRepository; 24 | 25 | @Test 26 | @Transactional 27 | public void testChangeUserDetails() { 28 | User user = createFormUser(); 29 | SessionDto sessionDto = emailLoginCommandHandler.handle(CommandObjectMother.emailLoginCommand()); 30 | 31 | ChangeUserDetailsCommand command = new ChangeUserDetailsCommand( 32 | user.getUserId().id(), 33 | "first name", 34 | "last name"); 35 | command.setAuthToken(sessionDto.getAccessToken()); 36 | 37 | commandHandler.handle(command); 38 | User userFromDb = userRepository.findById(user.getUserId()); 39 | assertEquals(userFromDb.getFirstName(), "first name"); 40 | assertEquals(userFromDb.getLastName(), "last name"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/integration/application/users/GetUserQueryHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.integration.application.users; 2 | 3 | import com.tomo.mcauthentication.application.authentication.dto.SessionDto; 4 | import com.tomo.mcauthentication.application.users.GetUserQueryHandler; 5 | import com.tomo.mcauthentication.application.users.query.GetUserQuery; 6 | import com.tomo.mcauthentication.integration.application.AbstractApplicationServiceTest; 7 | import org.junit.Test; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | 10 | import javax.transaction.Transactional; 11 | 12 | import static org.junit.Assert.assertNotNull; 13 | 14 | public class GetUserQueryHandlerTest extends AbstractApplicationServiceTest { 15 | 16 | @Autowired 17 | GetUserQueryHandler getUserQueryHandler; 18 | 19 | @Test 20 | @Transactional 21 | public void testGetUser() { 22 | SessionDto sessionDto = formLogin(); 23 | 24 | GetUserQuery query = new GetUserQuery(sessionDto.getUserId()); 25 | assertNotNull(getUserQueryHandler.handle(query)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/smoke/McAuthenticationApplicationSmokeTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.smoke; 2 | 3 | import com.tomo.mcauthentication.infrastructure.springboot.controller.UserController; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | 11 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 12 | class McAuthenticationApplicationSmokeTest { 13 | 14 | @Autowired 15 | UserController userController; 16 | 17 | @Test 18 | void contextLoads() { 19 | assertThat(userController).isNotNull(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/testdata/CommandObjectMother.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.testdata; 2 | 3 | import com.github.javafaker.Faker; 4 | import com.tomo.mcauthentication.application.authentication.command.EmailLoginCommand; 5 | import com.tomo.mcauthentication.application.authentication.command.FacebookLoginCommand; 6 | import com.tomo.mcauthentication.application.authentication.command.GoogleLoginCommand; 7 | import com.tomo.mcauthentication.application.recovery.command.CreatePasswordRecoveryCodeCommand; 8 | import com.tomo.mcauthentication.application.registration.command.RegisterNewUserCommand; 9 | 10 | public class CommandObjectMother extends StaticFields { 11 | 12 | private static Faker faker = new Faker(); 13 | 14 | private CommandObjectMother() { 15 | } 16 | 17 | public static RegisterNewUserCommand registerNewUserCommand() { 18 | return new RegisterNewUserCommand(USER_FIRST_NAME, USER_LAST_NAME, USER_EMAIL, PASSWORD); 19 | } 20 | 21 | public static RegisterNewUserCommand registerNewUserCommandWithFakerEmail() { 22 | return new RegisterNewUserCommand(USER_FIRST_NAME, USER_LAST_NAME, faker.internet().emailAddress(), PASSWORD); 23 | } 24 | 25 | public static EmailLoginCommand emailLoginCommand() { 26 | return new EmailLoginCommand(USER_EMAIL, PASSWORD); 27 | } 28 | 29 | public static FacebookLoginCommand facebookLoginCommand() { 30 | return new FacebookLoginCommand(ACCESS_CODE); 31 | } 32 | 33 | public static GoogleLoginCommand googleLoginCommand() { 34 | return new GoogleLoginCommand(ACCESS_CODE); 35 | } 36 | 37 | public static CreatePasswordRecoveryCodeCommand createPasswordRecoveryCodeCommand() { 38 | return new CreatePasswordRecoveryCodeCommand(USER_EMAIL); 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/testdata/StaticFields.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.testdata; 2 | 3 | public class StaticFields { 4 | 5 | public static final String ACCESS_CODE = "anAccessCode"; 6 | public static final String USER_OAUTH_ID = "anAccessCode"; 7 | public static final String USER_FIRST_NAME = "Tom"; 8 | public static final String USER_LAST_NAME = "Land"; 9 | public static final String USER_EMAIL = "random@email.com"; 10 | public static final String PASSWORD = "AA123bb##"; 11 | public static final String NEW_PASS = "randomNewPass123"; 12 | public static final String RECOVERY_CODE = "randomNewPass123"; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/AbstractUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain; 2 | 3 | import org.junit.jupiter.api.TestInstance; 4 | import org.junit.runner.RunWith; 5 | import org.mockito.MockitoSession; 6 | import org.mockito.junit.MockitoJUnitRunner; 7 | import org.springframework.test.context.ActiveProfiles; 8 | 9 | @RunWith(MockitoJUnitRunner.StrictStubs.class) 10 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 11 | @ActiveProfiles(profiles = { "unit" }) 12 | public abstract class AbstractUnitTest { 13 | 14 | protected MockitoSession mockito; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/registration/rules/PasswordRecoveryCodeShouldBeExpiredOrNullTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.registration.rules; 2 | 3 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 4 | import com.tomo.mcauthentication.domain.registration.rules.PasswordRecoveryCodeShouldBeExpiredOrNull; 5 | import com.tomo.mcauthentication.unit.domain.AbstractUnitTest; 6 | import org.junit.Test; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class PasswordRecoveryCodeShouldBeExpiredOrNullTest extends AbstractUnitTest { 14 | 15 | @Test 16 | public void testRuleIsNotBroken() { 17 | UserRegistration userRegistration = new UserRegistration(); 18 | userRegistration.setRecoveryCodeExpirationDate(LocalDateTime.now().minusSeconds(60)); 19 | 20 | assertTrue((new PasswordRecoveryCodeShouldBeExpiredOrNull(userRegistration)).isRuleComplied()); 21 | assertTrue((new PasswordRecoveryCodeShouldBeExpiredOrNull(new UserRegistration())).isRuleComplied()); 22 | } 23 | 24 | @Test 25 | public void testRuleIsBroken() { 26 | UserRegistration userRegistration = new UserRegistration(); 27 | userRegistration.setRecoveryCodeExpirationDate(LocalDateTime.now().plusSeconds(60)); 28 | userRegistration.setRecoveryCode("123"); 29 | 30 | assertFalse((new PasswordRecoveryCodeShouldBeExpiredOrNull(userRegistration)).isRuleComplied()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/registration/rules/PasswordRecoveryCodeShouldNotExpiredTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.registration.rules; 2 | 3 | import com.tomo.mcauthentication.domain.registration.UserRegistration; 4 | import com.tomo.mcauthentication.domain.registration.rules.PasswordRecoveryCodeShouldNotExpired; 5 | import com.tomo.mcauthentication.unit.domain.AbstractUnitTest; 6 | import org.junit.Test; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class PasswordRecoveryCodeShouldNotExpiredTest extends AbstractUnitTest { 14 | 15 | @Test 16 | public void testRuleIsNotBroken() { 17 | UserRegistration userRegistration = new UserRegistration(); 18 | userRegistration.setRecoveryCodeExpirationDate(LocalDateTime.now().plusSeconds(60)); 19 | assertTrue((new PasswordRecoveryCodeShouldNotExpired(userRegistration)).isRuleComplied()); 20 | } 21 | 22 | @Test 23 | public void testRuleIsBroken() { 24 | UserRegistration userRegistration = new UserRegistration(); 25 | userRegistration.setRecoveryCodeExpirationDate(LocalDateTime.now()); 26 | 27 | assertFalse((new PasswordRecoveryCodeShouldNotExpired(userRegistration)).isRuleComplied()); 28 | assertFalse((new PasswordRecoveryCodeShouldNotExpired(new UserRegistration())).isRuleComplied()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/registration/rules/PasswordsMustMatchTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.registration.rules; 2 | 3 | import com.tomo.mcauthentication.domain.registration.rules.PasswordsMustMatch; 4 | import com.tomo.mcauthentication.unit.domain.AbstractUnitTest; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertFalse; 8 | import static org.junit.Assert.assertTrue; 9 | 10 | public class PasswordsMustMatchTest extends AbstractUnitTest { 11 | 12 | @Test 13 | public void testRuleIsNotBroken() { 14 | assertTrue((new PasswordsMustMatch("abc", "abc")).isRuleComplied()); 15 | } 16 | 17 | @Test 18 | public void testRuleIsBroken() { 19 | assertFalse((new PasswordsMustMatch("abc1", "abc")).isRuleComplied()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/registration/rules/RecoveryCodeMustMatchTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.registration.rules; 2 | 3 | import com.tomo.mcauthentication.domain.registration.rules.RecoveryCodeMustMatch; 4 | import com.tomo.mcauthentication.unit.domain.AbstractUnitTest; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertFalse; 8 | import static org.junit.Assert.assertTrue; 9 | 10 | public class RecoveryCodeMustMatchTest extends AbstractUnitTest { 11 | 12 | @Test 13 | public void testRuleIsNotBroken() { 14 | assertTrue((new RecoveryCodeMustMatch("abc", "abc")).isRuleComplied()); 15 | } 16 | 17 | @Test 18 | public void testRuleIsBroken() { 19 | assertFalse((new RecoveryCodeMustMatch("abc1", "abc")).isRuleComplied()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/registration/rules/UserRegistrationCannotBeConfirmedAfterExpirationTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.registration.rules; 2 | 3 | import com.tomo.mcauthentication.domain.registration.rules.UserRegistrationCannotBeConfirmedAfterExpiration; 4 | import com.tomo.mcauthentication.unit.domain.AbstractUnitTest; 5 | import org.junit.Test; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | import static com.tomo.mcauthentication.domain.registration.rules.UserRegistrationCannotBeConfirmedAfterExpiration.CONFIRMATION_LINK_DURATION; 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class UserRegistrationCannotBeConfirmedAfterExpirationTest extends AbstractUnitTest { 14 | 15 | @Test 16 | public void testRuleIsNotBroken() { 17 | LocalDateTime registerDate1 = LocalDateTime.now(); 18 | assertTrue((new UserRegistrationCannotBeConfirmedAfterExpiration(registerDate1)).isRuleComplied()); 19 | 20 | LocalDateTime registerDate2 = LocalDateTime.now().minusDays(CONFIRMATION_LINK_DURATION).plusSeconds(5); 21 | assertTrue((new UserRegistrationCannotBeConfirmedAfterExpiration(registerDate2)).isRuleComplied()); 22 | } 23 | 24 | @Test 25 | public void testRuleIsBroken() { 26 | LocalDateTime registerDate1 = LocalDateTime.now().minusDays(CONFIRMATION_LINK_DURATION); 27 | assertFalse((new UserRegistrationCannotBeConfirmedAfterExpiration(registerDate1)).isRuleComplied()); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/registration/rules/UserRegistrationCannotBeConfirmedMoreThanOnceTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.registration.rules; 2 | 3 | import com.tomo.mcauthentication.domain.registration.UserRegistrationStatus; 4 | import com.tomo.mcauthentication.domain.registration.rules.UserRegistrationCannotBeConfirmedMoreThanOnce; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertFalse; 8 | import static org.junit.Assert.assertTrue; 9 | 10 | public class UserRegistrationCannotBeConfirmedMoreThanOnceTest { 11 | @Test 12 | public void testRuleIsNotBroken() { 13 | assertTrue((new UserRegistrationCannotBeConfirmedMoreThanOnce(UserRegistrationStatus.WaitingForConfirmation)).isRuleComplied()); 14 | assertTrue((new UserRegistrationCannotBeConfirmedMoreThanOnce(UserRegistrationStatus.Expired)).isRuleComplied()); 15 | } 16 | 17 | @Test 18 | public void testRuleIsBroken() { 19 | assertFalse((new UserRegistrationCannotBeConfirmedMoreThanOnce(UserRegistrationStatus.Confirmed)).isRuleComplied()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/registration/rules/UserRegistrationMustBeConfirmedTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.registration.rules; 2 | 3 | import com.tomo.mcauthentication.domain.registration.UserRegistrationStatus; 4 | import com.tomo.mcauthentication.domain.registration.rules.UserRegistrationMustBeConfirmed; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertFalse; 8 | import static org.junit.Assert.assertTrue; 9 | 10 | public class UserRegistrationMustBeConfirmedTest { 11 | 12 | @Test 13 | public void testRuleIsNotBroken() { 14 | assertTrue((new UserRegistrationMustBeConfirmed(UserRegistrationStatus.Confirmed)).isRuleComplied()); 15 | } 16 | 17 | @Test 18 | public void testRuleIsBroken() { 19 | assertFalse((new UserRegistrationMustBeConfirmed(UserRegistrationStatus.WaitingForConfirmation)).isRuleComplied()); 20 | assertFalse((new UserRegistrationMustBeConfirmed(UserRegistrationStatus.Expired)).isRuleComplied()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/registration/rules/UserRegistrationMustBeUniqueTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.registration.rules; 2 | 3 | import com.tomo.mcauthentication.domain.registration.UserRegistrationRepository; 4 | import com.tomo.mcauthentication.domain.registration.rules.UserRegistrationMustBeUnique; 5 | import com.tomo.mcauthentication.unit.domain.AbstractUnitTest; 6 | import org.junit.Test; 7 | import org.mockito.Mockito; 8 | 9 | import static org.junit.Assert.assertFalse; 10 | import static org.junit.Assert.assertTrue; 11 | import static org.mockito.Mockito.any; 12 | import static org.mockito.Mockito.when; 13 | 14 | public class UserRegistrationMustBeUniqueTest extends AbstractUnitTest { 15 | 16 | UserRegistrationRepository repository = Mockito.mock(UserRegistrationRepository.class); 17 | 18 | @Test 19 | public void testRuleIsNotBroken() { 20 | when(repository.countByEmailAndStatus(any(), any())).thenReturn(0L); 21 | assertTrue((new UserRegistrationMustBeUnique(repository, "")).isRuleComplied()); 22 | } 23 | 24 | @Test 25 | public void testRuleIsBroken() { 26 | when(repository.countByEmailAndStatus(any(), any())).thenReturn(1L); 27 | assertFalse((new UserRegistrationMustBeUnique(repository, "")).isRuleComplied()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/session/rules/SessionCannotBeExpiredWhenRefreshTokenIsMissingTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.session.rules; 2 | 3 | import com.tomo.mcauthentication.domain.session.Session; 4 | import com.tomo.mcauthentication.domain.session.rule.SessionCannotBeExpiredWhenRefreshTokenIsMissing; 5 | import com.tomo.mcauthentication.unit.domain.AbstractUnitTest; 6 | import org.junit.Test; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class SessionCannotBeExpiredWhenRefreshTokenIsMissingTest extends AbstractUnitTest { 14 | 15 | @Test 16 | public void testRuleIsNotBroken() { 17 | Session session1 = new Session(); 18 | session1.setExpirationDate(LocalDateTime.now().plusDays(2)); 19 | 20 | 21 | Session session2 = new Session(); 22 | session2.setExpirationDate(LocalDateTime.now().minusDays(2)); 23 | session2.setRefreshToken("randomToken"); 24 | 25 | assertTrue((new SessionCannotBeExpiredWhenRefreshTokenIsMissing(session1)).isRuleComplied()); 26 | assertTrue((new SessionCannotBeExpiredWhenRefreshTokenIsMissing(session2)).isRuleComplied()); 27 | } 28 | 29 | @Test 30 | public void testRuleIsBroken() { 31 | Session session1 = new Session(); 32 | session1.setExpirationDate(LocalDateTime.now().minusDays(2)); 33 | 34 | assertFalse((new SessionCannotBeExpiredWhenRefreshTokenIsMissing(session1)).isRuleComplied()); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/unit/domain/user/rules/UserEmailMustBeUniqueTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.unit.domain.user.rules; 2 | 3 | import com.tomo.mcauthentication.domain.users.User; 4 | import com.tomo.mcauthentication.domain.users.UserRepository; 5 | import com.tomo.mcauthentication.domain.users.rules.UserEmailMustBeUnique; 6 | import com.tomo.mcauthentication.unit.domain.AbstractUnitTest; 7 | import org.junit.Test; 8 | import org.mockito.Mockito; 9 | 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | import static org.mockito.ArgumentMatchers.any; 13 | import static org.mockito.Mockito.when; 14 | 15 | public class UserEmailMustBeUniqueTest extends AbstractUnitTest { 16 | 17 | UserRepository repository = Mockito.mock(UserRepository.class); 18 | 19 | @Test 20 | public void testRuleIsNotBroken() { 21 | when(repository.findByEmail(any())).thenReturn(null); 22 | assertTrue((new UserEmailMustBeUnique(repository, "random@email.com")).isRuleComplied()); 23 | } 24 | 25 | @Test 26 | public void testRuleIsBroken() { 27 | when(repository.findByEmail(any())).thenReturn(new User()); 28 | assertFalse((new UserEmailMustBeUnique(repository, "random@email.com")).isRuleComplied()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/weblayer/BaseWebLayerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.weblayer; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | import org.springframework.context.annotation.Profile; 6 | import org.springframework.test.context.TestPropertySource; 7 | import org.springframework.test.context.junit4.SpringRunner; 8 | 9 | @RunWith(SpringRunner.class) 10 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 11 | public abstract class BaseWebLayerTest { } 12 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/weblayer/springboot/controller/AbstractControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.weblayer.springboot.controller; 2 | 3 | import com.tomo.ddd.email.EmailSender; 4 | 5 | import com.tomo.mcauthentication.weblayer.BaseWebLayerTest; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 8 | import org.springframework.boot.test.mock.mockito.MockBean; 9 | import org.springframework.boot.web.server.LocalServerPort; 10 | import org.springframework.http.HttpHeaders; 11 | import org.springframework.test.web.servlet.MockMvc; 12 | 13 | import java.net.URI; 14 | import java.net.URISyntaxException; 15 | 16 | @AutoConfigureMockMvc 17 | public abstract class AbstractControllerTest extends BaseWebLayerTest { 18 | 19 | @MockBean 20 | protected EmailSender emailMessageSender; 21 | 22 | @LocalServerPort 23 | protected int randomServerPort; 24 | 25 | @Autowired 26 | protected MockMvc mockMvc; 27 | 28 | protected URI url(String uri) throws URISyntaxException { 29 | final String baseUrl = "http://localhost:" + randomServerPort+ uri; 30 | return new URI(baseUrl); 31 | } 32 | 33 | protected HttpHeaders baseHeaders() { 34 | HttpHeaders headers = new org.springframework.http.HttpHeaders(); 35 | headers.set("X-COM-PERSIST", "true"); 36 | return headers; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/tomo/mcauthentication/weblayer/springboot/controller/RegistrationControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.tomo.mcauthentication.weblayer.springboot.controller; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.tomo.mcauthentication.application.registration.command.RegisterNewUserCommand; 5 | import com.tomo.mcauthentication.infrastructure.springboot.controller.RestApiRoutes.RegistrationRoutes; 6 | import com.tomo.mcauthentication.testdata.CommandObjectMother; 7 | 8 | import org.junit.Test; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | 11 | import javax.transaction.Transactional; 12 | 13 | import static org.springframework.http.MediaType.APPLICATION_JSON; 14 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 15 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 16 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 17 | 18 | public class RegistrationControllerTest extends AbstractControllerTest { 19 | 20 | @Autowired 21 | private ObjectMapper objectMapper; 22 | 23 | @Test 24 | @Transactional 25 | public void shouldCreateUserRegistration() throws Exception { 26 | RegisterNewUserCommand command = CommandObjectMother.registerNewUserCommandWithFakerEmail(); 27 | this.mockMvc.perform( 28 | post(RegistrationRoutes.FORM_REGISTRATION) 29 | .contentType(APPLICATION_JSON) 30 | .content(objectMapper.writeValueAsString(command))) 31 | .andDo(print()) 32 | .andExpect(status().isCreated()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/resources/application-ci.yml: -------------------------------------------------------------------------------- 1 | debug: true 2 | 3 | spring: 4 | datasource: 5 | url: jdbc:postgresql://mc-authentication-db-test:5432/mc_authentication --------------------------------------------------------------------------------