├── .github └── workflows │ ├── boot.yml │ ├── ci.yml │ └── release-to-maven-central.yml ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── commons-logo.svg └── email │ ├── email-change-email.png │ ├── email-change-password.png │ ├── email-invite.png │ └── email-verify.png ├── commons-auth-adapter ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── config │ │ └── AuthAdapterAutoConfiguration.java │ │ ├── filter │ │ ├── JwtTokenFilter.java │ │ └── LoginCookieFilter.java │ │ ├── handler │ │ ├── LoginSuccessCookieHandler.java │ │ └── LogoutCookieHandler.java │ │ └── security │ │ ├── LoginAuthenticationProvider.java │ │ └── TokenAuthenticationProvider.java │ └── resources │ └── META-INF │ ├── spring.factories │ └── spring │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports ├── commons-auth-api.ts ├── commons-auth-api ├── pom.xml └── src │ ├── doc │ └── swagger │ │ └── api-docs.json │ ├── main │ └── java │ │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── adapters │ │ ├── JwtClientRequestFactory.java │ │ ├── JwtRestTemplate.java │ │ ├── JwtTokenProvider.java │ │ └── SimpleJwtTokenProvider.java │ │ ├── api │ │ ├── AppInviteApi.java │ │ ├── AppUserApi.java │ │ ├── AuthenticationApi.java │ │ ├── ForgotPasswordApi.java │ │ ├── ImpersonateApi.java │ │ ├── InviteApi.java │ │ ├── LoginApi.java │ │ ├── RegistrationApi.java │ │ ├── UserSearchApi.java │ │ └── ValidationApi.java │ │ ├── convert │ │ ├── AuthQueryConverter.java │ │ ├── QueryAppInviteConverter.java │ │ └── QueryAppUserConverter.java │ │ ├── dto │ │ ├── ExpirationInfo.java │ │ ├── appinvite │ │ │ ├── AppInviteRead.java │ │ │ ├── ConfirmInviteRequest.java │ │ │ ├── InviteRequest.java │ │ │ └── QueryAppInvite.java │ │ ├── appuser │ │ │ ├── AppUserCreate.java │ │ │ ├── AppUserRead.java │ │ │ ├── AppUserResetPassword.java │ │ │ ├── AppUserUpdate.java │ │ │ └── QueryAppUser.java │ │ ├── authentication │ │ │ ├── EmailChangeRequest.java │ │ │ ├── JwtTokenBundle.java │ │ │ ├── LoginRequest.java │ │ │ ├── LoginResponse.java │ │ │ ├── OAuthLoginResponse.java │ │ │ ├── PasswordChangeRequest.java │ │ │ ├── UpdateProfileRequest.java │ │ │ └── UsernameChangeRequest.java │ │ ├── forgot │ │ │ ├── ForgotPasswordRequest.java │ │ │ └── PerformPasswordResetRequest.java │ │ ├── registration │ │ │ └── RegistrationRequest.java │ │ └── validation │ │ │ ├── EmailErrorCodes.java │ │ │ ├── PasswordErrorCodes.java │ │ │ ├── TokenErrorCodes.java │ │ │ ├── UsernameErrorCodes.java │ │ │ └── ValidationResponse.java │ │ ├── exception │ │ ├── AuthErrorCodes.java │ │ ├── BaseValidationException.java │ │ ├── EmailValidationException.java │ │ ├── PasswordValidationException.java │ │ ├── RegistrationException.java │ │ ├── TokenRefreshException.java │ │ ├── UnknownUserException.java │ │ ├── UsernameValidationException.java │ │ ├── ValidationErrorCode.java │ │ └── VerificationException.java │ │ ├── model │ │ ├── AppUserReference.java │ │ ├── AppUserToken.java │ │ ├── SimpleAppUserReference.java │ │ └── SimpleAppUserToken.java │ │ ├── resource │ │ ├── AppInviteResource.java │ │ ├── AppUserResource.java │ │ ├── AuthenticationResource.java │ │ ├── ForgotPasswordResource.java │ │ ├── ImpersonateResource.java │ │ ├── InviteResource.java │ │ ├── LoginResource.java │ │ ├── RegistrationResource.java │ │ ├── UserSearchResource.java │ │ └── ValidationResource.java │ │ └── util │ │ ├── AbstractJwtTokenStore.java │ │ ├── JwtTokenBody.java │ │ ├── JwtTokenDecoder.java │ │ ├── JwtTokenStore.java │ │ ├── JwtTokenStoreHttp.java │ │ └── UsernameGenerator.java │ └── test │ └── java │ └── io │ └── rocketbase │ └── commons │ ├── dto │ └── authentication │ │ └── JwtTokenBundleTest.java │ └── util │ ├── JwtTokenDecoderTest.java │ └── UsernameGeneratorTest.java ├── commons-auth-core ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── adapters │ │ ├── AuthClientLoginRequestFactory.java │ │ ├── AuthClientRequestFactory.java │ │ └── AuthRestTemplate.java │ │ ├── config │ │ ├── AuthProperties.java │ │ ├── EmailProperties.java │ │ ├── FormsProperties.java │ │ ├── GravatarProperties.java │ │ ├── JwtProperties.java │ │ ├── PasswordProperties.java │ │ ├── RegistrationProperties.java │ │ └── UsernameProperties.java │ │ ├── converter │ │ ├── AppInviteConverter.java │ │ ├── AppUserConverter.java │ │ └── ValidationConverter.java │ │ ├── event │ │ ├── ActiveUserChangedEvent.java │ │ ├── EmailChangeEvent.java │ │ ├── ImpersonateEvent.java │ │ ├── InviteEvent.java │ │ ├── LoginEvent.java │ │ ├── PasswordEvent.java │ │ ├── RefreshTokenEvent.java │ │ ├── RegistrationEvent.java │ │ ├── RequestMeEvent.java │ │ ├── UpdateProfileEvent.java │ │ └── UsernameChangeEvent.java │ │ ├── model │ │ ├── AppInviteEntity.java │ │ ├── AppUserEntity.java │ │ └── EntityWithKeyValue.java │ │ ├── security │ │ ├── CommonsAuthenticationToken.java │ │ ├── CommonsPrincipal.java │ │ ├── CustomAuthoritiesProvider.java │ │ ├── EmptyCustomAuthoritiesProvider.java │ │ └── JwtTokenService.java │ │ ├── service │ │ ├── AppInvitePersistenceService.java │ │ ├── AppUserPersistenceService.java │ │ ├── FeedbackActionService.java │ │ ├── JwtTokenStoreProvider.java │ │ ├── KeyGenerator.java │ │ ├── SimpleTokenService.java │ │ ├── ValidationUserLookupService.java │ │ ├── avatar │ │ │ ├── AvatarService.java │ │ │ └── GravatarService.java │ │ ├── email │ │ │ ├── AuthEmailService.java │ │ │ ├── EmailAddress.java │ │ │ ├── EmailLogSender.java │ │ │ └── EmailSender.java │ │ └── user │ │ │ ├── ActiveUserStore.java │ │ │ └── ActiveUserStoreLocalCache.java │ │ └── util │ │ └── RolesAuthoritiesConverter.java │ └── test │ ├── java │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── security │ │ └── JwtTokenServiceTest.java │ │ └── service │ │ ├── GravatarServiceTest.java │ │ └── user │ │ └── ActiveUserStoreLocalCacheTest.java │ └── resources │ └── application-test.yml ├── commons-auth-email-postmark ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── config │ │ └── AuthEmailPostmarkAutoConfiguration.java │ │ └── service │ │ └── email │ │ └── EmailPostmarkSender.java │ └── resources │ └── META-INF │ ├── spring.factories │ └── spring │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports ├── commons-auth-email-smtp ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── config │ │ └── AuthEmailSmtpAutoConfiguration.java │ │ └── service │ │ └── email │ │ └── EmailSmtpSender.java │ └── resources │ └── META-INF │ ├── spring.factories │ └── spring │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports ├── commons-auth-forms ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── config │ │ └── AuthFormAutoConfiguration.java │ │ └── controller │ │ ├── AbstractFormsController.java │ │ ├── AuthFormsController.java │ │ ├── InviteFormsController.java │ │ ├── RegistrationFormsController.java │ │ └── VerifyChangeFormsController.java │ └── resources │ ├── META-INF │ ├── resources │ │ └── assets │ │ │ ├── commons-auth.css │ │ │ └── rocketbase.svg │ ├── spring.factories │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ ├── messages.properties │ ├── messages_de.properties │ └── templates │ ├── email-change-success.html │ ├── forgot-submitted.html │ ├── forgot.html │ ├── invite-success.html │ ├── invite.html │ ├── login.html │ ├── registration-success.html │ ├── registration-verification.html │ ├── registration.html │ ├── reset-password-success.html │ └── reset-password.html ├── commons-auth-jpa ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── rocketbase │ │ │ └── commons │ │ │ ├── config │ │ │ └── AuthJpaAutoConfiguration.java │ │ │ ├── model │ │ │ ├── AppInviteJpaEntity.java │ │ │ ├── AppUserJpaEntity.java │ │ │ └── converter │ │ │ │ └── StringListConverter.java │ │ │ ├── repository │ │ │ ├── AppInviteJpaRepository.java │ │ │ └── AppUserJpaRepository.java │ │ │ └── service │ │ │ ├── AppInviteJpaServiceImpl.java │ │ │ ├── AppUserJpaServiceImpl.java │ │ │ └── PredicateHelper.java │ └── resources │ │ └── META-INF │ │ ├── spring.factories │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ ├── java │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── Application.java │ │ ├── TestSecurityConfig.java │ │ └── service │ │ ├── AppInviteJpaServiceImplTest.java │ │ └── AppUserJpaServiceImplTest.java │ └── resources │ └── application.yml ├── commons-auth-mongo ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── rocketbase │ │ │ └── commons │ │ │ ├── config │ │ │ └── AuthMongoAutoConfiguration.java │ │ │ ├── model │ │ │ ├── AppInviteMongoEntity.java │ │ │ └── AppUserMongoEntity.java │ │ │ └── service │ │ │ ├── AppInviteMongoServiceImpl.java │ │ │ └── AppUserMongoServiceImpl.java │ └── resources │ │ └── META-INF │ │ ├── spring.factories │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ ├── java │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── Application.java │ │ ├── TestSecurityConfig.java │ │ └── service │ │ ├── AppInviteMongoServiceImplTest.java │ │ ├── AppUserMongoServiceImplTest.java │ │ └── BaseIntegrationTest.java │ └── resources │ └── application.yml ├── commons-auth-server ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── rocketbase │ │ │ └── commons │ │ │ ├── config │ │ │ └── AuthServerAutoConfiguration.java │ │ │ └── controller │ │ │ ├── AppInviteController.java │ │ │ ├── AppUserController.java │ │ │ ├── AuthenticationController.java │ │ │ ├── ForgotPasswordController.java │ │ │ ├── ImpersonateController.java │ │ │ ├── InviteController.java │ │ │ ├── OAuthLoginRefreshController.java │ │ │ ├── RegistrationController.java │ │ │ ├── UserSearchController.java │ │ │ ├── ValidationController.java │ │ │ └── exceptionhandler │ │ │ ├── EmailValidationExceptionHandler.java │ │ │ ├── PasswordValidationExceptionHandler.java │ │ │ ├── RegistrationExceptionHandler.java │ │ │ ├── UnknownUserExceptionHandler.java │ │ │ ├── UsernameValidationExceptionHandler.java │ │ │ └── VerificationExceptionHandler.java │ └── resources │ │ └── META-INF │ │ ├── resources │ │ └── favicon.ico │ │ ├── spring.factories │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ ├── java │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── BaseIntegrationTestPrefixed.java │ │ ├── TestApplication.java │ │ ├── TestSecurityConfig.java │ │ ├── controller │ │ ├── AppUserControllerTest.java │ │ ├── AuthenticationControllerTest.java │ │ ├── ForgotPasswordControllerTest.java │ │ ├── ImpersonateControllerTest.java │ │ ├── RegistrationControllerTest.java │ │ ├── UserSearchControllerTest.java │ │ └── ValidationControllerTest.java │ │ ├── security │ │ └── CustomAuthoritiesProviderTest.java │ │ └── service │ │ └── ActiveUserStoreIntegrationTest.java │ └── resources │ └── application-test.yml ├── commons-auth-service ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── rocketbase │ │ │ └── commons │ │ │ ├── api │ │ │ ├── AppInviteApiService.java │ │ │ ├── AppUserApiService.java │ │ │ ├── AuthenticationApiService.java │ │ │ ├── BaseApiService.java │ │ │ ├── ForgotPasswordApiService.java │ │ │ ├── ImpersonateApiService.java │ │ │ ├── InviteApiService.java │ │ │ ├── LoginApiService.java │ │ │ ├── RegistrationApiService.java │ │ │ ├── UserSearchApiService.java │ │ │ └── ValidationApiService.java │ │ │ ├── config │ │ │ ├── AuthApiAutoConfiguration.java │ │ │ └── AuthServiceAutoConfiguration.java │ │ │ ├── filter │ │ │ └── JwtAuthenticationTokenFilter.java │ │ │ ├── service │ │ │ ├── auth │ │ │ │ ├── DefaultLoginService.java │ │ │ │ └── LoginService.java │ │ │ ├── change │ │ │ │ ├── ChangeAppUserWithConfirmService.java │ │ │ │ └── DefaultChangeAppUserWithConfirmService.java │ │ │ ├── email │ │ │ │ ├── DefaultEmailService.java │ │ │ │ ├── DefaultMailContentConfig.java │ │ │ │ └── MailContentConfig.java │ │ │ ├── forgot │ │ │ │ ├── AppUserForgotPasswordService.java │ │ │ │ └── DefaultAppUserForgotPasswordService.java │ │ │ ├── impersonate │ │ │ │ ├── DefaultImpersonateService.java │ │ │ │ └── ImpersonateService.java │ │ │ ├── invite │ │ │ │ ├── AppInviteService.java │ │ │ │ └── DefaultAppInviteService.java │ │ │ ├── registration │ │ │ │ ├── DefaultRegistrationService.java │ │ │ │ └── RegistrationService.java │ │ │ ├── user │ │ │ │ ├── AppUserService.java │ │ │ │ └── DefaultAppUserService.java │ │ │ └── validation │ │ │ │ ├── DefaultValidationService.java │ │ │ │ ├── ValidationErrorCodeService.java │ │ │ │ └── ValidationService.java │ │ │ └── util │ │ │ └── JwtTokenStoreService.java │ └── resources │ │ ├── META-INF │ │ ├── spring.factories │ │ └── spring │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ ├── auth_messages.properties │ │ └── auth_messages_de.properties │ └── test │ ├── java │ └── io │ │ └── rocketbase │ │ └── commons │ │ ├── Application.java │ │ ├── TestSecurityConfig.java │ │ └── service │ │ ├── DefaultValidationServiceTest.java │ │ ├── FeedbackActionServiceTest.java │ │ └── email │ │ ├── EmailServiceTest.java │ │ └── MailContentConfigTest.java │ └── resources │ └── application-test.yml ├── commons-auth-test ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── rocketbase │ │ └── commons │ │ └── test │ │ ├── AppInvitePersistenceTestService.java │ │ ├── AppUserPersistenceTestService.java │ │ ├── BaseIntegrationTest.java │ │ ├── EmailSenderTest.java │ │ ├── ModifiedJwtTokenService.java │ │ ├── adapters │ │ └── AuthRestTestTemplate.java │ │ └── model │ │ ├── AppInviteTestEntity.java │ │ └── AppUserTestEntity.java │ └── test │ └── java │ └── io │ └── rocketbase │ └── commons │ ├── converter │ └── AppUserConverterTest.java │ └── security │ └── JwtTokenServiceTest.java ├── coverage └── pom.xml ├── lombok.config └── pom.xml /.github/workflows/boot.yml: -------------------------------------------------------------------------------- 1 | name: spring-boot-compatibility 2 | on: [ push, pull_request ] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | strategy: 7 | matrix: 8 | spring-boot: [ '2.5.14', '2.6.12', '2.7.9' ] 9 | name: Spring Boot ${{ matrix.spring-boot }} 10 | steps: 11 | - uses: actions/checkout@v3 12 | 13 | - name: Set up Java 14 | uses: actions/setup-java@v3 15 | with: 16 | java-version: '11' 17 | distribution: 'temurin' 18 | cache: 'maven' 19 | 20 | - name: Run Spring Boot tests 21 | run: mvn -B -Dspring-boot.version=${{ matrix.spring-boot }} -PspringBootDevelopment clean test --file pom.xml 22 | env: 23 | TZ: UTC 24 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [ push, pull_request ] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | strategy: 7 | matrix: 8 | java: [ '11', '17', '19' ] 9 | name: Temurin ${{ matrix.java }} 10 | steps: 11 | - uses: actions/checkout@v3 12 | 13 | - name: Set up Java ${{ matrix.java }} 14 | uses: actions/setup-java@v3 15 | with: 16 | java-version: ${{ matrix.java }} 17 | distribution: 'temurin' 18 | cache: 'maven' 19 | 20 | - name: Run all tests 21 | run: mvn -B clean test 22 | env: 23 | TZ: UTC 24 | -------------------------------------------------------------------------------- /.github/workflows/release-to-maven-central.yml: -------------------------------------------------------------------------------- 1 | name: release-to-maven-central 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | releaseversion: 6 | description: 'Release version' 7 | required: true 8 | default: '1.0.0' 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - run: | 15 | echo "Release version ${{ github.event.inputs.releaseversion }}!" 16 | 17 | - uses: actions/checkout@v2 18 | 19 | - name: Set up Maven Central Repository 20 | uses: actions/setup-java@v1 21 | with: 22 | java-version: 11 23 | server-id: ossrh 24 | server-username: MAVEN_USERNAME 25 | server-password: MAVEN_PASSWORD 26 | gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} 27 | gpg-passphrase: MAVEN_GPG_PASSPHRASE 28 | 29 | - name: Set projects Maven version to GitHub Action GUI set version 30 | run: mvn versions:set "-DnewVersion=${{ github.event.inputs.releaseversion }}" 31 | 32 | - name: Publish package 33 | run: mvn --batch-mode clean deploy -P release -DskipTests=true 34 | env: 35 | MAVEN_USERNAME: ${{ secrets.OSS_SONATYPE_USERNAME }} 36 | MAVEN_PASSWORD: ${{ secrets.OSS_SONATYPE_PASSWORD }} 37 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} 38 | 39 | - name: Create GitHub Release 40 | id: create_release 41 | uses: actions/create-release@v1 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | with: 45 | tag_name: ${{ github.event.inputs.releaseversion }} 46 | release_name: ${{ github.event.inputs.releaseversion }} 47 | body: | 48 | New version ${{ github.event.inputs.releaseversion }} published 49 | draft: false 50 | prerelease: false 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | # Idea 25 | .idea 26 | *iml 27 | 28 | target/ 29 | node_modules 30 | package-lock.json 31 | package.json 32 | webpack.config.js 33 | webpack.generated.js -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 rocketbase.io software productions GmbH 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 | -------------------------------------------------------------------------------- /assets/email/email-change-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocketbase-io/commons-auth/c86f5c1caba8c63f9f91fd4828395162f35f23bc/assets/email/email-change-email.png -------------------------------------------------------------------------------- /assets/email/email-change-password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocketbase-io/commons-auth/c86f5c1caba8c63f9f91fd4828395162f35f23bc/assets/email/email-change-password.png -------------------------------------------------------------------------------- /assets/email/email-invite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocketbase-io/commons-auth/c86f5c1caba8c63f9f91fd4828395162f35f23bc/assets/email/email-invite.png -------------------------------------------------------------------------------- /assets/email/email-verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocketbase-io/commons-auth/c86f5c1caba8c63f9f91fd4828395162f35f23bc/assets/email/email-verify.png -------------------------------------------------------------------------------- /commons-auth-adapter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | commons-auth 7 | io.rocketbase.commons 8 | LATEST-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | commons-auth-adapter 13 | 14 | 15 | 16 | io.rocketbase.commons 17 | commons-auth-core 18 | ${project.version} 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-autoconfigure 23 | true 24 | 25 | 26 | org.springframework.security 27 | spring-security-config 28 | true 29 | 30 | 31 | org.springframework.security 32 | spring-security-web 33 | true 34 | 35 | 36 | javax.servlet 37 | javax.servlet-api 38 | true 39 | 40 | 41 | javax.annotation 42 | javax.annotation-api 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /commons-auth-adapter/src/main/java/io/rocketbase/commons/handler/LoginSuccessCookieHandler.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.handler; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | import io.rocketbase.commons.security.CommonsAuthenticationToken; 5 | import io.rocketbase.commons.util.JwtTokenStore; 6 | import org.springframework.security.core.Authentication; 7 | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; 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.time.Instant; 15 | 16 | public class LoginSuccessCookieHandler extends SavedRequestAwareAuthenticationSuccessHandler { 17 | 18 | public static final String AUTH_REMEMBER = "authRemember"; 19 | 20 | @Override 21 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { 22 | if (authentication instanceof CommonsAuthenticationToken) { 23 | JwtTokenStore jwtTokenStore = ((CommonsAuthenticationToken) authentication).getJwtTokenStore(); 24 | if (jwtTokenStore != null) { 25 | JwtTokenBundle tokenBundle = jwtTokenStore.getTokenBundle(); 26 | if (tokenBundle != null && tokenBundle.getRefreshTokenExpiryDate() != null) { 27 | Cookie authRemember = new Cookie(AUTH_REMEMBER, tokenBundle.getRefreshToken()); 28 | authRemember.setMaxAge((int) (tokenBundle.getRefreshTokenExpiryDate().getEpochSecond() - Instant.now().getEpochSecond())); 29 | authRemember.setHttpOnly(false); 30 | authRemember.setPath("/"); 31 | response.addCookie(authRemember); 32 | } 33 | } 34 | } 35 | super.onAuthenticationSuccess(request, response, authentication); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /commons-auth-adapter/src/main/java/io/rocketbase/commons/handler/LogoutCookieHandler.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.handler; 2 | 3 | import io.rocketbase.commons.filter.LoginCookieFilter; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.security.core.Authentication; 6 | import org.springframework.security.web.authentication.logout.LogoutHandler; 7 | import org.springframework.web.util.WebUtils; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | @Slf4j 13 | public class LogoutCookieHandler implements LogoutHandler { 14 | 15 | @Override 16 | public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { 17 | if (WebUtils.getCookie(request, LoginSuccessCookieHandler.AUTH_REMEMBER) != null) { 18 | LoginCookieFilter.removeAuthCookie(response); 19 | log.debug("removed authRemeber cookie after logout"); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /commons-auth-adapter/src/main/java/io/rocketbase/commons/security/TokenAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.security; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.springframework.security.authentication.AuthenticationProvider; 5 | import org.springframework.security.core.Authentication; 6 | import org.springframework.security.core.AuthenticationException; 7 | 8 | @RequiredArgsConstructor 9 | public class TokenAuthenticationProvider implements AuthenticationProvider { 10 | 11 | @Override 12 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 13 | return authentication; 14 | } 15 | 16 | @Override 17 | public boolean supports(Class authentication) { 18 | return CommonsAuthenticationToken.class.isAssignableFrom(authentication); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /commons-auth-adapter/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | io.rocketbase.commons.config.AuthAdapterAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-adapter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.rocketbase.commons.config.AuthAdapterAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/adapters/JwtRestTemplate.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.adapters; 2 | 3 | import io.rocketbase.commons.resource.BasicResponseErrorHandler; 4 | import lombok.Getter; 5 | import org.springframework.http.client.ClientHttpRequestFactory; 6 | import org.springframework.web.client.RestOperations; 7 | import org.springframework.web.client.RestTemplate; 8 | import org.springframework.web.util.UriComponentsBuilder; 9 | 10 | public class JwtRestTemplate extends RestTemplate implements RestOperations { 11 | 12 | @Getter 13 | private JwtTokenProvider tokenProvider; 14 | 15 | /** 16 | * default constructor
17 | * set's {@link BasicResponseErrorHandler} as errorHandler 18 | * 19 | * @param tokenProvider will get used to init an {@link JwtClientRequestFactory} 20 | */ 21 | public JwtRestTemplate(JwtTokenProvider tokenProvider) { 22 | super(new JwtClientRequestFactory(tokenProvider)); 23 | this.tokenProvider = tokenProvider; 24 | setErrorHandler(new BasicResponseErrorHandler()); 25 | } 26 | 27 | /** 28 | * us in case you would like provide your own factory 29 | * 30 | * @param factory custom factory 31 | */ 32 | public JwtRestTemplate(ClientHttpRequestFactory factory) { 33 | super(factory); 34 | } 35 | 36 | public UriComponentsBuilder getBaseAuthApiBuilder() { 37 | if (tokenProvider != null) { 38 | String baseAuthApiUrl = tokenProvider.getBaseAuthApiUrl(); 39 | return UriComponentsBuilder.fromUriString(baseAuthApiUrl + (baseAuthApiUrl.endsWith("/") ? "" : "/")); 40 | } 41 | return UriComponentsBuilder.newInstance(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/adapters/JwtTokenProvider.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.adapters; 2 | 3 | public interface JwtTokenProvider { 4 | 5 | String getToken(); 6 | 7 | void setToken(String token); 8 | 9 | String getRefreshToken(); 10 | 11 | String getBaseAuthApiUrl(); 12 | } 13 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/adapters/SimpleJwtTokenProvider.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.adapters; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class SimpleJwtTokenProvider implements JwtTokenProvider { 8 | 9 | private String token; 10 | private String refreshToken; 11 | private String baseAuthApiUrl; 12 | 13 | public SimpleJwtTokenProvider(String baseAuthApiUrl) { 14 | this.baseAuthApiUrl = baseAuthApiUrl; 15 | } 16 | 17 | public SimpleJwtTokenProvider(String baseAuthApiUrl, JwtTokenBundle jwtTokenBundle) { 18 | this.baseAuthApiUrl = baseAuthApiUrl; 19 | this.token = jwtTokenBundle.getToken(); 20 | this.refreshToken = jwtTokenBundle.getRefreshToken(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/AppInviteApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.PageableResult; 4 | import io.rocketbase.commons.dto.appinvite.AppInviteRead; 5 | import io.rocketbase.commons.dto.appinvite.InviteRequest; 6 | import io.rocketbase.commons.dto.appinvite.QueryAppInvite; 7 | import org.springframework.data.domain.Pageable; 8 | 9 | public interface AppInviteApi { 10 | 11 | PageableResult find(QueryAppInvite query, Pageable pageable); 12 | 13 | AppInviteRead invite(InviteRequest inviteRequest); 14 | 15 | void delete(String id); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/AppUserApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.PageableResult; 4 | import io.rocketbase.commons.dto.appinvite.AppInviteRead; 5 | import io.rocketbase.commons.dto.appinvite.InviteRequest; 6 | import io.rocketbase.commons.dto.appuser.*; 7 | import org.springframework.data.domain.PageRequest; 8 | import org.springframework.data.domain.Pageable; 9 | 10 | import java.util.Optional; 11 | 12 | public interface AppUserApi { 13 | 14 | @Deprecated 15 | default PageableResult find(int page, int pagesize) { 16 | return find(PageRequest.of(page, pagesize)); 17 | } 18 | 19 | default PageableResult find(Pageable pageable) { 20 | return find(null, pageable); 21 | } 22 | 23 | PageableResult find(QueryAppUser query, Pageable pageable); 24 | 25 | Optional findOne(String usernameOrId); 26 | 27 | AppUserRead create(AppUserCreate create); 28 | 29 | AppUserRead resetPassword(String usernameOrId, AppUserResetPassword reset); 30 | 31 | AppUserRead patch(String usernameOrId, AppUserUpdate update); 32 | 33 | void delete(String id); 34 | 35 | AppInviteRead invite(InviteRequest inviteRequest); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/AuthenticationApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.ExpirationInfo; 4 | import io.rocketbase.commons.dto.appuser.AppUserRead; 5 | import io.rocketbase.commons.dto.authentication.EmailChangeRequest; 6 | import io.rocketbase.commons.dto.authentication.PasswordChangeRequest; 7 | import io.rocketbase.commons.dto.authentication.UpdateProfileRequest; 8 | import io.rocketbase.commons.dto.authentication.UsernameChangeRequest; 9 | import io.rocketbase.commons.exception.EmailValidationException; 10 | import io.rocketbase.commons.exception.UsernameValidationException; 11 | 12 | public interface AuthenticationApi { 13 | 14 | AppUserRead getAuthenticated(); 15 | 16 | void changePassword(PasswordChangeRequest passwordChange); 17 | 18 | AppUserRead changeUsername(UsernameChangeRequest usernameChange) throws UsernameValidationException; 19 | 20 | ExpirationInfo changeEmail(EmailChangeRequest emailChange) throws EmailValidationException; 21 | 22 | AppUserRead verifyEmail(String verification); 23 | 24 | void updateProfile(UpdateProfileRequest updateProfile); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/ForgotPasswordApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.ExpirationInfo; 4 | import io.rocketbase.commons.dto.appuser.AppUserRead; 5 | import io.rocketbase.commons.dto.forgot.ForgotPasswordRequest; 6 | import io.rocketbase.commons.dto.forgot.PerformPasswordResetRequest; 7 | 8 | public interface ForgotPasswordApi { 9 | 10 | ExpirationInfo forgotPassword(ForgotPasswordRequest forgotPassword); 11 | 12 | void resetPassword(PerformPasswordResetRequest performPasswordReset); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/ImpersonateApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | 5 | public interface ImpersonateApi { 6 | 7 | JwtTokenBundle impersonate(String userIdOrUsername); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/InviteApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.appinvite.AppInviteRead; 4 | import io.rocketbase.commons.dto.appinvite.ConfirmInviteRequest; 5 | import io.rocketbase.commons.dto.appuser.AppUserRead; 6 | 7 | public interface InviteApi { 8 | 9 | AppInviteRead verify(String inviteId); 10 | 11 | AppUserRead transformToUser(ConfirmInviteRequest confirmInvite); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/LoginApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.adapters.JwtTokenProvider; 4 | import io.rocketbase.commons.dto.authentication.LoginRequest; 5 | import io.rocketbase.commons.dto.authentication.LoginResponse; 6 | 7 | public interface LoginApi { 8 | 9 | LoginResponse login(LoginRequest login); 10 | 11 | String getNewAccessToken(String refreshToken); 12 | 13 | default void refreshAccessToken(JwtTokenProvider tokenProvider) { 14 | String accessToken = getNewAccessToken(tokenProvider.getRefreshToken()); 15 | tokenProvider.setToken(accessToken); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/RegistrationApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.ExpirationInfo; 4 | import io.rocketbase.commons.dto.appuser.AppUserRead; 5 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 6 | import io.rocketbase.commons.dto.registration.RegistrationRequest; 7 | 8 | public interface RegistrationApi { 9 | 10 | ExpirationInfo register(RegistrationRequest registration); 11 | 12 | JwtTokenBundle verify(String verification); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/UserSearchApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.PageableResult; 4 | import io.rocketbase.commons.dto.appuser.QueryAppUser; 5 | import io.rocketbase.commons.model.AppUserReference; 6 | import lombok.SneakyThrows; 7 | import org.springframework.data.domain.Pageable; 8 | 9 | import java.util.Optional; 10 | 11 | public interface UserSearchApi { 12 | @SneakyThrows 13 | PageableResult search(QueryAppUser query, Pageable pageable); 14 | 15 | Optional findByUsernameOrId(String usernameOrId); 16 | } 17 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/api/ValidationApi.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.validation.*; 4 | 5 | public interface ValidationApi { 6 | ValidationResponse validatePassword(String password); 7 | 8 | ValidationResponse validateUsername(String username); 9 | 10 | ValidationResponse validateEmail(String email); 11 | 12 | ValidationResponse validateToken(String token); 13 | } 14 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/convert/AuthQueryConverter.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.convert; 2 | 3 | import org.springframework.util.MultiValueMap; 4 | import org.springframework.util.StringUtils; 5 | import org.springframework.web.util.UriComponentsBuilder; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public interface AuthQueryConverter { 11 | 12 | default Map parseKeyValue(String key, MultiValueMap params) { 13 | Map result = new HashMap<>(); 14 | if (params != null && params.containsKey(key)) { 15 | for (String kv : params.get(key)) { 16 | String[] split = StringUtils.split(kv, ";"); 17 | if (split != null) { 18 | result.put(split[0], split[1]); 19 | } 20 | } 21 | } 22 | return result; 23 | } 24 | 25 | default void addKeyValues(UriComponentsBuilder uriBuilder, String key, Map keyValues) { 26 | if (uriBuilder != null && key != null && keyValues != null && !keyValues.isEmpty()) { 27 | for (Map.Entry entry : keyValues.entrySet()) { 28 | uriBuilder.queryParam(key, String.format("%s;%s", entry.getKey(), entry.getValue())); 29 | } 30 | } 31 | } 32 | 33 | default void addString(UriComponentsBuilder uriBuilder, String key, String value) { 34 | if (uriBuilder != null && value != null && key != null) { 35 | uriBuilder.queryParam(key, value); 36 | } 37 | } 38 | 39 | T fromParams(MultiValueMap params); 40 | 41 | UriComponentsBuilder addParams(UriComponentsBuilder uriBuilder, T query); 42 | } 43 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/convert/QueryAppInviteConverter.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.convert; 2 | 3 | import io.rocketbase.commons.dto.appinvite.QueryAppInvite; 4 | import org.springframework.util.MultiValueMap; 5 | import org.springframework.web.util.UriComponentsBuilder; 6 | 7 | import static io.rocketbase.commons.util.QueryParamBuilder.appendParams; 8 | import static io.rocketbase.commons.util.QueryParamParser.parseBoolean; 9 | 10 | public class QueryAppInviteConverter implements AuthQueryConverter { 11 | 12 | public QueryAppInvite fromParams(MultiValueMap params) { 13 | if (params == null) { 14 | return null; 15 | } 16 | return QueryAppInvite.builder() 17 | .invitor(params.containsKey("invitor") ? params.getFirst("invitor") : null) 18 | .email(params.containsKey("email") ? params.getFirst("email") : null) 19 | .expired(parseBoolean(params, "expired", null)) 20 | .keyValues(parseKeyValue("keyValue", params)) 21 | .build(); 22 | } 23 | 24 | public UriComponentsBuilder addParams(UriComponentsBuilder uriBuilder, QueryAppInvite query) { 25 | if (query != null) { 26 | addString(uriBuilder, "invitor", query.getInvitor()); 27 | addString(uriBuilder, "email", query.getEmail()); 28 | appendParams(uriBuilder, "expired", query.getExpired()); 29 | addKeyValues(uriBuilder, "keyValue", query.getKeyValues()); 30 | } 31 | return uriBuilder; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/ExpirationInfo.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import javax.annotation.Nullable; 10 | import java.io.Serializable; 11 | import java.time.Instant; 12 | 13 | /** 14 | * wrapper object related to expirations 15 | * @param detailed object 16 | */ 17 | @Data 18 | @Builder 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @Schema(description = "wrapper object related to expirations") 22 | public class ExpirationInfo implements Serializable { 23 | 24 | @Nullable 25 | private Instant expires; 26 | 27 | @Nullable 28 | private T detail; 29 | 30 | /** 31 | * duration in seconds after verification-link will expire 32 | */ 33 | @Nullable 34 | @Schema(description = "duration in seconds after verification-link will expire") 35 | public Long getExpiresAfter() { 36 | if (expires == null) { 37 | return null; 38 | } 39 | return Instant.now().getEpochSecond() - expires.getEpochSecond(); 40 | } 41 | 42 | public boolean isExpired() { 43 | return expires != null && Instant.now().isAfter(expires); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/appinvite/AppInviteRead.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.appinvite; 2 | 3 | import io.rocketbase.commons.model.HasFirstAndLastName; 4 | import io.rocketbase.commons.model.HasKeyValue; 5 | import io.swagger.v3.oas.annotations.media.Schema; 6 | import lombok.*; 7 | 8 | import java.time.Instant; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * database entity representation of invited persons 14 | */ 15 | @Data 16 | @Builder 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | @EqualsAndHashCode(of = "id") 20 | @Schema(description = "database entity representation of invited persons") 21 | public class AppInviteRead implements HasKeyValue, HasFirstAndLastName { 22 | private String id; 23 | 24 | @Schema(description = "name that will get displayed to person within email") 25 | private String invitor; 26 | 27 | @Schema(description = "custom message to the invited person") 28 | private String message; 29 | 30 | private String firstName; 31 | 32 | private String lastName; 33 | 34 | private String email; 35 | 36 | @Singular 37 | private List roles; 38 | 39 | @Singular 40 | private Map keyValues; 41 | 42 | private Instant created; 43 | 44 | private Instant expiration; 45 | } 46 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/appinvite/ConfirmInviteRequest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.appinvite; 2 | 3 | import io.rocketbase.commons.model.HasFirstAndLastName; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | import lombok.*; 6 | 7 | import javax.annotation.Nullable; 8 | import javax.validation.constraints.Email; 9 | import javax.validation.constraints.NotNull; 10 | import java.io.Serializable; 11 | 12 | /** 13 | * post body during invite confirm progress 14 | */ 15 | @Data 16 | @Builder 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | @ToString(exclude = {"password"}) 20 | @Schema(description = "post body during invite confirm progress") 21 | public class ConfirmInviteRequest implements Serializable, HasFirstAndLastName { 22 | 23 | @NotNull 24 | private String inviteId; 25 | 26 | @NotNull 27 | private String username; 28 | 29 | @Nullable 30 | private String firstName; 31 | 32 | @Nullable 33 | private String lastName; 34 | 35 | @NotNull 36 | @Email 37 | private String email; 38 | 39 | @NotNull 40 | private String password; 41 | } 42 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/appinvite/QueryAppInvite.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.appinvite; 2 | 3 | import io.rocketbase.commons.model.HasKeyValue; 4 | import lombok.*; 5 | 6 | import javax.annotation.Nullable; 7 | import java.io.Serializable; 8 | import java.util.Map; 9 | 10 | /** 11 | * query object to find invites 12 | * string properties mean search like ignore cases 13 | */ 14 | @Data 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | @Builder 18 | public class QueryAppInvite implements Serializable, HasKeyValue { 19 | 20 | @Nullable 21 | private String invitor; 22 | @Nullable 23 | private String email; 24 | @Nullable 25 | private Boolean expired; 26 | 27 | /** 28 | * search for given key and value with exact match ignore cases 29 | */ 30 | @Singular 31 | @Nullable 32 | private Map keyValues; 33 | } 34 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/appuser/AppUserCreate.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.appuser; 2 | 3 | import io.rocketbase.commons.model.HasFirstAndLastName; 4 | import io.rocketbase.commons.model.HasKeyValue; 5 | import io.swagger.v3.oas.annotations.media.Schema; 6 | import lombok.*; 7 | 8 | import javax.annotation.Nullable; 9 | import javax.validation.constraints.Email; 10 | import javax.validation.constraints.NotNull; 11 | import java.io.Serializable; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * post body to create a new user 17 | */ 18 | @Data 19 | @Builder 20 | @NoArgsConstructor 21 | @AllArgsConstructor 22 | @ToString(exclude = {"password"}) 23 | @Schema(description = "post body to create a new user") 24 | public class AppUserCreate implements Serializable, HasFirstAndLastName, HasKeyValue { 25 | 26 | @NotNull 27 | private String username; 28 | 29 | @NotNull 30 | private String password; 31 | 32 | @Nullable 33 | private String firstName; 34 | 35 | @Nullable 36 | private String lastName; 37 | 38 | @NotNull 39 | @Email 40 | private String email; 41 | 42 | @Nullable 43 | private String avatar; 44 | 45 | @Singular 46 | @Nullable 47 | private Map keyValues; 48 | 49 | @Nullable 50 | private Boolean admin; 51 | 52 | @Singular 53 | @Nullable 54 | private List roles; 55 | 56 | @Builder.Default 57 | private boolean enabled = true; 58 | } 59 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/appuser/AppUserRead.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.appuser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 5 | import io.rocketbase.commons.model.AppUserReference; 6 | import io.rocketbase.commons.model.AppUserToken; 7 | import io.rocketbase.commons.model.SimpleAppUserReference; 8 | import io.swagger.v3.oas.annotations.media.Schema; 9 | import lombok.*; 10 | 11 | import javax.annotation.Nullable; 12 | import java.io.Serializable; 13 | import java.time.Instant; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * database entity representation of user 19 | */ 20 | @Data 21 | @Builder 22 | @NoArgsConstructor 23 | @AllArgsConstructor 24 | @EqualsAndHashCode(of = "id") 25 | @JsonDeserialize(as = AppUserRead.class) 26 | @Schema(description = "database entity representation of user") 27 | public class AppUserRead implements AppUserToken, Serializable { 28 | 29 | private String id; 30 | 31 | private String username; 32 | 33 | @Nullable 34 | private String firstName; 35 | 36 | @Nullable 37 | private String lastName; 38 | 39 | private String email; 40 | 41 | @Nullable 42 | private String avatar; 43 | 44 | private List roles; 45 | 46 | @Nullable 47 | private Map keyValues; 48 | 49 | private boolean enabled; 50 | 51 | private Instant created; 52 | 53 | @Nullable 54 | private Instant lastLogin; 55 | 56 | @JsonIgnore 57 | public AppUserReference toReference() { 58 | return SimpleAppUserReference.builder() 59 | .id(getId()) 60 | .username(getUsername()) 61 | .firstName(getFirstName()) 62 | .lastName(getLastName()) 63 | .email(getEmail()) 64 | .avatar(getAvatar()) 65 | .build(); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/appuser/AppUserResetPassword.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.appuser; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import lombok.*; 5 | 6 | import javax.validation.constraints.NotNull; 7 | import java.io.Serializable; 8 | 9 | /** 10 | * post body for rest-password 11 | */ 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | @ToString(exclude = {"resetPassword"}) 17 | @Schema(description = "post body for rest-password") 18 | public class AppUserResetPassword implements Serializable { 19 | 20 | @NotNull 21 | private String resetPassword; 22 | } 23 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/appuser/AppUserUpdate.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.appuser; 2 | 3 | import io.rocketbase.commons.model.HasFirstAndLastName; 4 | import io.rocketbase.commons.model.HasKeyValue; 5 | import io.swagger.v3.oas.annotations.media.Schema; 6 | import lombok.*; 7 | 8 | import javax.annotation.Nullable; 9 | import java.io.Serializable; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * post body for update user. null properties mean let value as it is 15 | */ 16 | @Data 17 | @Builder 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | @ToString(exclude = {"password"}) 21 | @Schema(description = "post body for update user. null properties mean let value as it is") 22 | public class AppUserUpdate implements Serializable, HasKeyValue, HasFirstAndLastName { 23 | 24 | @Nullable 25 | private String password; 26 | 27 | @Nullable 28 | private String firstName; 29 | 30 | @Nullable 31 | private String lastName; 32 | 33 | @Nullable 34 | private String avatar; 35 | 36 | @Nullable 37 | private List roles; 38 | 39 | /** 40 | * will removed key that have value of null
41 | * will only add/replace new/existing key values
42 | * not mentioned key will still stay the same 43 | */ 44 | @Singular 45 | @Nullable 46 | @Schema(description = "will removed key that have value of null.\n" + 47 | "will only add/replace new/existing key values.\n" + 48 | "not mentioned key will still stay the same") 49 | private Map keyValues; 50 | 51 | @Nullable 52 | private Boolean enabled; 53 | } 54 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/appuser/QueryAppUser.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.appuser; 2 | 3 | import io.rocketbase.commons.model.HasFirstAndLastName; 4 | import io.rocketbase.commons.model.HasKeyValue; 5 | import io.rocketbase.commons.util.Nulls; 6 | import lombok.*; 7 | import org.springframework.data.annotation.Transient; 8 | 9 | import javax.annotation.Nullable; 10 | import java.io.Serializable; 11 | import java.util.Map; 12 | 13 | /** 14 | * query object to find user 15 | * string properties mean search like ignore cases 16 | */ 17 | @Data 18 | @AllArgsConstructor 19 | @NoArgsConstructor 20 | @Builder 21 | public class QueryAppUser implements Serializable, HasKeyValue, HasFirstAndLastName { 22 | 23 | @Nullable 24 | private String username; 25 | @Nullable 26 | private String firstName; 27 | @Nullable 28 | private String lastName; 29 | @Nullable 30 | private String email; 31 | 32 | /** 33 | * search for given key and value with exact match ignore cases 34 | */ 35 | @Singular 36 | @Nullable 37 | private Map keyValues; 38 | 39 | /** 40 | * searches for all properties containing text 41 | */ 42 | @Nullable 43 | private String freetext; 44 | /** 45 | * used needs to have role ignore cases 46 | */ 47 | @Nullable 48 | private String hasRole; 49 | @Nullable 50 | private Boolean enabled; 51 | 52 | @Transient 53 | public boolean isEmpty() { 54 | return !Nulls.anyNoneNullValue(username, firstName, lastName, email, keyValues, freetext, hasRole, enabled); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/authentication/EmailChangeRequest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.authentication; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import javax.validation.constraints.Email; 10 | import javax.validation.constraints.NotNull; 11 | import java.io.Serializable; 12 | 13 | /** 14 | * body for email change 15 | */ 16 | @Data 17 | @Builder 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | @Schema(description = "body for email change") 21 | public class EmailChangeRequest implements Serializable { 22 | 23 | @NotNull 24 | @Email 25 | private String newEmail; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/authentication/JwtTokenBundle.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.authentication; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import io.rocketbase.commons.util.JwtTokenBody; 6 | import io.rocketbase.commons.util.JwtTokenDecoder; 7 | import io.swagger.v3.oas.annotations.media.Schema; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Builder; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | 13 | import javax.validation.constraints.NotNull; 14 | import java.io.Serializable; 15 | import java.time.Instant; 16 | 17 | /** 18 | * holds two tokens. one with short live-time for use and one to generate new short-tokens... 19 | */ 20 | @Data 21 | @Builder 22 | @NoArgsConstructor 23 | @AllArgsConstructor 24 | @Schema(description = "holds two tokens. one with short live-time for use and one to generate new short-tokens...") 25 | public class JwtTokenBundle implements Serializable { 26 | 27 | /** 28 | * token with short live-time that is used for api-calls 29 | */ 30 | @NotNull 31 | @Schema(description = "token with short live-time that is used for api-calls") 32 | private String token; 33 | 34 | /** 35 | * used to generate new tokens - could not be used for normal api-calls 36 | */ 37 | @NotNull 38 | @Schema(description = "used to generate new tokens - could not be used for normal api-calls") 39 | private String refreshToken; 40 | 41 | @JsonIgnore 42 | public Instant getAccessTokenExpiryDate() { 43 | JwtTokenBody body = JwtTokenDecoder.decodeTokenBody(token); 44 | return body.getExpiration(); 45 | } 46 | 47 | @JsonIgnore 48 | public Instant getRefreshTokenExpiryDate() { 49 | JwtTokenBody body = JwtTokenDecoder.decodeTokenBody(refreshToken); 50 | return body.getExpiration(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/authentication/LoginRequest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.authentication; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import lombok.*; 5 | 6 | import javax.validation.constraints.NotNull; 7 | import java.io.Serializable; 8 | 9 | /** 10 | * body for login 11 | */ 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | @ToString(exclude = {"password"}) 17 | @Schema(description = "body for login") 18 | public class LoginRequest implements Serializable { 19 | 20 | @NotNull 21 | private String username; 22 | 23 | @NotNull 24 | private String password; 25 | } 26 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/authentication/LoginResponse.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.authentication; 2 | 3 | import io.rocketbase.commons.dto.appuser.AppUserRead; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | import javax.validation.constraints.NotNull; 11 | import java.io.Serializable; 12 | 13 | /** 14 | * response after successful login 15 | */ 16 | @Data 17 | @Builder 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | @Schema(description = "response after successful login") 21 | public class LoginResponse implements Serializable { 22 | 23 | @NotNull 24 | private JwtTokenBundle jwtTokenBundle; 25 | 26 | @NotNull 27 | private AppUserRead user; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/authentication/OAuthLoginResponse.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.authentication; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.io.Serializable; 10 | 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class OAuthLoginResponse implements Serializable { 16 | 17 | @JsonProperty("token_type") 18 | private String tokenType; 19 | 20 | private String scope; 21 | 22 | @JsonProperty("expires_in") 23 | private Long expiresIn; 24 | 25 | @JsonProperty("access_token") 26 | private String accessToken; 27 | 28 | @JsonProperty("refresh_expires_in") 29 | private Long refreshExpiresIn; 30 | 31 | @JsonProperty("refresh_token") 32 | private String refreshToken; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/authentication/PasswordChangeRequest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.authentication; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import lombok.*; 5 | 6 | import javax.validation.constraints.NotNull; 7 | import java.io.Serializable; 8 | 9 | /** 10 | * body for password change 11 | */ 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | @ToString(exclude = {"currentPassword", "newPassword"}) 17 | @Schema(description = "body for password change") 18 | public class PasswordChangeRequest implements Serializable { 19 | 20 | @NotNull 21 | private String currentPassword; 22 | 23 | @NotNull 24 | private String newPassword; 25 | } 26 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/authentication/UpdateProfileRequest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.authentication; 2 | 3 | import io.rocketbase.commons.model.AppUserReference; 4 | import io.rocketbase.commons.model.HasFirstAndLastName; 5 | import io.rocketbase.commons.model.HasKeyValue; 6 | import io.swagger.v3.oas.annotations.media.Schema; 7 | import lombok.*; 8 | 9 | import javax.annotation.Nullable; 10 | import java.io.Serializable; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * body for user update profile 16 | */ 17 | @Data 18 | @Builder 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @Schema(description = "body for user update profile") 22 | public class UpdateProfileRequest implements Serializable, HasKeyValue, HasFirstAndLastName { 23 | 24 | @Nullable 25 | private String firstName; 26 | 27 | @Nullable 28 | private String lastName; 29 | 30 | @Nullable 31 | private String avatar; 32 | 33 | /** 34 | * will removed key that have value of null
35 | * will only add/replace new/existing key values
36 | * not mentioned key will still stay the same 37 | */ 38 | @Nullable 39 | @Singular 40 | @Schema(description = "will removed key that have value of null.\n" + 41 | "will only add/replace new/existing key values.\n" + 42 | "not mentioned key will still stay the same") 43 | private Map keyValues; 44 | 45 | public static UpdateProfileRequest init(AppUserReference user) { 46 | return UpdateProfileRequest.builder() 47 | .firstName(user.getFirstName()) 48 | .lastName(user.getLastName()) 49 | .avatar(user.getAvatar()) 50 | .keyValues(new HashMap<>()) 51 | .build(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/authentication/UsernameChangeRequest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.authentication; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import javax.validation.constraints.NotNull; 10 | import java.io.Serializable; 11 | 12 | /** 13 | * body to change username 14 | */ 15 | @Data 16 | @Builder 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | @Schema(description = "body to change username") 20 | public class UsernameChangeRequest implements Serializable { 21 | 22 | @NotNull 23 | private String newUsername; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/forgot/ForgotPasswordRequest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.forgot; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import javax.annotation.Nullable; 10 | import javax.validation.constraints.Email; 11 | import java.io.Serializable; 12 | 13 | /** 14 | * body of password forgot process 15 | */ 16 | @Data 17 | @Builder 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | @Schema(description = "body of password forgot process") 21 | public class ForgotPasswordRequest implements Serializable { 22 | 23 | @Nullable 24 | private String username; 25 | 26 | @Email 27 | @Nullable 28 | private String email; 29 | 30 | /** 31 | * optional parameter to overwrite system default 32 | *

33 | * full qualified url to a custom UI that proceed the password reset
34 | * * ?verification=VALUE will get append 35 | */ 36 | @Nullable 37 | @Schema(description = "optional parameter to overwrite system default\n" + 38 | "full qualified url to a custom UI that proceed the password reset.\n" + 39 | "* ?verification=VALUE will get append") 40 | private String resetPasswordUrl; 41 | 42 | 43 | /** 44 | * please use resetPasswordUrl will get removed in future 45 | */ 46 | @Deprecated 47 | @Nullable 48 | @Schema(description = "please use resetPasswordUrl will get removed in future", deprecated = true) 49 | private String verificationUrl; 50 | } 51 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/forgot/PerformPasswordResetRequest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.forgot; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import lombok.*; 5 | 6 | import javax.validation.constraints.NotNull; 7 | import java.io.Serializable; 8 | 9 | /** 10 | * body for password change after forgot triggered 11 | */ 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | @ToString(exclude = {"password"}) 17 | @Schema(description = "body for password change after forgot triggered") 18 | public class PerformPasswordResetRequest implements Serializable { 19 | 20 | @NotNull 21 | private String verification; 22 | 23 | @NotNull 24 | private String password; 25 | } 26 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/registration/RegistrationRequest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.registration; 2 | 3 | import io.rocketbase.commons.model.HasFirstAndLastName; 4 | import io.rocketbase.commons.model.HasKeyValue; 5 | import io.swagger.v3.oas.annotations.media.Schema; 6 | import lombok.*; 7 | 8 | import javax.annotation.Nullable; 9 | import javax.validation.constraints.Email; 10 | import javax.validation.constraints.NotNull; 11 | import java.io.Serializable; 12 | import java.util.Map; 13 | 14 | /** 15 | * body for registration as new user 16 | */ 17 | @Data 18 | @Builder 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @ToString(exclude = {"password"}) 22 | @Schema(description = "body for registration as new user") 23 | public class RegistrationRequest implements Serializable, HasKeyValue, HasFirstAndLastName { 24 | 25 | @NotNull 26 | private String username; 27 | 28 | @Nullable 29 | private String firstName; 30 | 31 | @Nullable 32 | private String lastName; 33 | 34 | @NotNull 35 | @Email 36 | private String email; 37 | 38 | @NotNull 39 | private String password; 40 | 41 | @Nullable 42 | private Map keyValues; 43 | 44 | /** 45 | * optional parameter to overwrite system default 46 | *

47 | * full qualified url to a custom UI that proceed the verification
48 | * * ?verification=VALUE will get append 49 | */ 50 | @Nullable 51 | @Schema(description = "optional parameter to overwrite system default.\n" + 52 | "full qualified url to a custom UI that proceed the verification.\n" + 53 | "* ?verification=VALUE will get append") 54 | private String verificationUrl; 55 | } 56 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/EmailErrorCodes.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.validation; 2 | 3 | import com.fasterxml.jackson.annotation.JsonValue; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | 6 | @Schema(enumAsRef = true) 7 | public enum EmailErrorCodes { 8 | ALREADY_TAKEN("alreadyTaken"), 9 | INVALID("invalid"), 10 | TOO_LONG("tooLong"); 11 | 12 | private final String value; 13 | 14 | EmailErrorCodes(String value) { 15 | this.value = value; 16 | } 17 | 18 | @JsonValue 19 | public String getValue() { 20 | return value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/PasswordErrorCodes.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.validation; 2 | 3 | import com.fasterxml.jackson.annotation.JsonValue; 4 | 5 | public enum PasswordErrorCodes { 6 | TOO_SHORT("tooShort"), 7 | TOO_LONG("tooLong"), 8 | INSUFFICIENT_LOWERCASE("insufficientLowercase"), 9 | INSUFFICIENT_UPPERCASE("insufficientUppercase"), 10 | INSUFFICIENT_DIGIT("insufficientDigit"), 11 | INSUFFICIENT_SPECIAL("insufficientSpecial"), 12 | INVALID_CURRENT_PASSWORD("invalidCurrentPassword"); 13 | 14 | private final String value; 15 | 16 | PasswordErrorCodes(String value) { 17 | this.value = value; 18 | } 19 | 20 | @JsonValue 21 | public String getValue() { 22 | return value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/TokenErrorCodes.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.validation; 2 | 3 | import com.fasterxml.jackson.annotation.JsonValue; 4 | 5 | public enum TokenErrorCodes { 6 | EXPIRED("expired"), 7 | INVALID("invalid"); 8 | 9 | private final String value; 10 | 11 | TokenErrorCodes(String value) { 12 | this.value = value; 13 | } 14 | 15 | @JsonValue 16 | public String getValue() { 17 | return value; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/UsernameErrorCodes.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.validation; 2 | 3 | import com.fasterxml.jackson.annotation.JsonValue; 4 | 5 | public enum UsernameErrorCodes { 6 | ALREADY_TAKEN("alreadyTaken"), 7 | TOO_SHORT("tooShort"), 8 | TOO_LONG("tooLong"), 9 | NOT_ALLOWED_CHAR("notAllowedChar"); 10 | 11 | private final String value; 12 | 13 | UsernameErrorCodes(String value) { 14 | this.value = value; 15 | } 16 | 17 | @JsonValue 18 | public String getValue() { 19 | return value; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/ValidationResponse.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.dto.validation; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.annotation.JsonSubTypes; 5 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 6 | import com.google.common.base.Joiner; 7 | import lombok.*; 8 | 9 | import java.io.Serializable; 10 | import java.util.Map; 11 | 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@type") 17 | @JsonSubTypes({ 18 | @JsonSubTypes.Type(value = UsernameErrorCodes.class, name = "username"), 19 | @JsonSubTypes.Type(value = PasswordErrorCodes.class, name = "password"), 20 | @JsonSubTypes.Type(value = EmailErrorCodes.class, name = "email"), 21 | @JsonSubTypes.Type(value = TokenErrorCodes.class, name = "token")}) 22 | public class ValidationResponse implements Serializable { 23 | 24 | private boolean valid; 25 | 26 | @Singular 27 | private Map errorCodes; 28 | 29 | @JsonIgnore 30 | public String getMessage(String separator) { 31 | if (!errorCodes.isEmpty()) { 32 | return Joiner.on(separator).join(errorCodes.values()); 33 | } 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/AuthErrorCodes.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | import com.fasterxml.jackson.annotation.JsonValue; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | import lombok.Getter; 6 | import lombok.RequiredArgsConstructor; 7 | 8 | @RequiredArgsConstructor 9 | @Schema(enumAsRef = true) 10 | public enum AuthErrorCodes { 11 | REGISTRATION(1010, "registration"), 12 | VERIFICATION_INVALID(1011, "verificationInvalid"), 13 | UNKNOWN_USER(1012, "unknownUser"), 14 | VALIDATION(1013, "validation"); 15 | 16 | @Getter 17 | private final int status; 18 | private final String value; 19 | 20 | @JsonValue 21 | public String getValue() { 22 | return value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/BaseValidationException.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | import com.google.common.base.Joiner; 4 | 5 | import java.util.Set; 6 | import java.util.stream.Collectors; 7 | 8 | public interface BaseValidationException> { 9 | Set> getErrors(); 10 | 11 | /** 12 | * joins all error message to one string
13 | * returns empty string when no errors exist 14 | */ 15 | default String getErrorsMessage() { 16 | if (getErrors() != null) { 17 | return Joiner.on("; ").skipNulls().join(getErrors().stream().map(e -> e.getMessage()).collect(Collectors.toList())); 18 | } 19 | return ""; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/EmailValidationException.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | import io.rocketbase.commons.dto.validation.EmailErrorCodes; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.util.Set; 9 | 10 | @Getter 11 | @ToString 12 | @RequiredArgsConstructor 13 | public class EmailValidationException extends RuntimeException implements BaseValidationException { 14 | 15 | private final Set> errors; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/PasswordValidationException.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | import io.rocketbase.commons.dto.validation.PasswordErrorCodes; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.util.Set; 9 | 10 | @Getter 11 | @ToString 12 | @RequiredArgsConstructor 13 | public class PasswordValidationException extends RuntimeException implements BaseValidationException { 14 | 15 | private final Set> errors; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/RegistrationException.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | import io.rocketbase.commons.dto.validation.EmailErrorCodes; 4 | import io.rocketbase.commons.dto.validation.PasswordErrorCodes; 5 | import io.rocketbase.commons.dto.validation.UsernameErrorCodes; 6 | import lombok.Getter; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.ToString; 9 | 10 | import java.util.LinkedHashSet; 11 | import java.util.Set; 12 | 13 | @Getter 14 | @ToString 15 | @RequiredArgsConstructor 16 | public class RegistrationException extends RuntimeException implements BaseValidationException { 17 | 18 | private final Set> usernameErrors; 19 | private final Set> passwordErrors; 20 | private final Set> emailErrors; 21 | 22 | @Override 23 | public Set getErrors() { 24 | Set result = new LinkedHashSet<>(); 25 | if (hasUsernameErrors()) { 26 | result.addAll(usernameErrors); 27 | } 28 | if (hasPasswordErrors()) { 29 | result.addAll(passwordErrors); 30 | } 31 | if (hasEmailErrors()) { 32 | result.addAll(emailErrors); 33 | } 34 | return null; 35 | } 36 | 37 | public boolean hasUsernameErrors() { 38 | return usernameErrors != null && !usernameErrors.isEmpty(); 39 | } 40 | 41 | public boolean hasPasswordErrors() { 42 | return passwordErrors != null && !passwordErrors.isEmpty(); 43 | } 44 | 45 | public boolean hasEmailErrors() { 46 | return emailErrors != null && !emailErrors.isEmpty(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/TokenRefreshException.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | public class TokenRefreshException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/UnknownUserException.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.ToString; 6 | 7 | @ToString 8 | @RequiredArgsConstructor 9 | @Getter 10 | public class UnknownUserException extends RuntimeException { 11 | 12 | private final boolean email; 13 | private final boolean username; 14 | } 15 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/UsernameValidationException.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | import io.rocketbase.commons.dto.validation.UsernameErrorCodes; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.util.Set; 9 | 10 | @Getter 11 | @ToString 12 | @RequiredArgsConstructor 13 | public class UsernameValidationException extends RuntimeException { 14 | 15 | private final Set> errors; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/ValidationErrorCode.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | 7 | @Getter 8 | @EqualsAndHashCode(of = "code") 9 | @RequiredArgsConstructor 10 | public class ValidationErrorCode> { 11 | 12 | private final T code; 13 | private final String field; 14 | private final String message; 15 | 16 | public ValidationErrorCode(T code) { 17 | this.code = code; 18 | message = null; 19 | field = null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/exception/VerificationException.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.exception; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.ToString; 6 | 7 | @ToString 8 | @Getter 9 | @RequiredArgsConstructor 10 | public class VerificationException extends RuntimeException { 11 | 12 | private final String field; 13 | } 14 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/model/AppUserReference.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 5 | import io.swagger.v3.oas.annotations.media.Schema; 6 | 7 | import javax.annotation.Nullable; 8 | import java.io.Serializable; 9 | 10 | /** 11 | * short representation of an appuser 12 | */ 13 | @JsonDeserialize(as = SimpleAppUserReference.class) 14 | @Schema(description = "short representation of an appuser") 15 | public interface AppUserReference extends HasFirstAndLastName, Serializable { 16 | 17 | String getId(); 18 | 19 | String getUsername(); 20 | 21 | String getEmail(); 22 | 23 | @Nullable 24 | String getAvatar(); 25 | 26 | /** 27 | * fullname fallback if null use username 28 | */ 29 | @JsonIgnore 30 | default String getDisplayName() { 31 | String fullName = getFullName(); 32 | if (fullName == null) { 33 | return getUsername(); 34 | } 35 | return fullName; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/model/AppUserToken.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.model; 2 | 3 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * AppUserReference + role information + keyValues 10 | */ 11 | @JsonDeserialize(as = SimpleAppUserToken.class) 12 | @Schema(description = "AppUserReference + role information + keyValues") 13 | public interface AppUserToken extends AppUserReference, HasKeyValue { 14 | 15 | List getRoles(); 16 | 17 | /** 18 | * checks if user has role with name (ignore cases) 19 | * 20 | * @param role name of role to search 21 | * @return true when exists 22 | */ 23 | default boolean hasRole(String role) { 24 | if (getRoles() != null && role != null) { 25 | for (String r : getRoles()) { 26 | if (role.equalsIgnoreCase(r)) { 27 | return true; 28 | } 29 | } 30 | } 31 | return false; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/model/SimpleAppUserReference.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.model; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * simplified AppUser without keyValues, password, audit etc...
7 | * used to store a simple representation as a copy of AppUser in mongo or elsewhere 8 | */ 9 | @Getter 10 | @Builder 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @EqualsAndHashCode(of = "id") 14 | public class SimpleAppUserReference implements AppUserReference { 15 | 16 | private String id; 17 | 18 | private String username; 19 | 20 | private String firstName; 21 | 22 | private String lastName; 23 | 24 | private String email; 25 | 26 | private String avatar; 27 | } 28 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/model/SimpleAppUserToken.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.model; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import lombok.*; 5 | 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @Builder 14 | public class SimpleAppUserToken implements AppUserToken { 15 | 16 | private String id; 17 | 18 | private String username; 19 | 20 | private String firstName; 21 | 22 | private String lastName; 23 | 24 | private String email; 25 | 26 | private String avatar; 27 | 28 | private List roles; 29 | 30 | @Getter(AccessLevel.PROTECTED) 31 | @Setter(AccessLevel.PROTECTED) 32 | private Map keyValueMap = new HashMap<>(); 33 | 34 | public SimpleAppUserToken(String id, String username, List roles) { 35 | this.id = id; 36 | this.username = username; 37 | this.roles = roles; 38 | } 39 | 40 | @Override 41 | public Map getKeyValues() { 42 | return getKeyValueMap() != null ? ImmutableMap.copyOf(getKeyValueMap()) : null; 43 | } 44 | 45 | @Override 46 | public void setKeyValues(Map map) { 47 | keyValueMap = map; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/resource/ImpersonateResource.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.resource; 2 | 3 | import io.rocketbase.commons.adapters.JwtRestTemplate; 4 | import io.rocketbase.commons.api.ImpersonateApi; 5 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 6 | import lombok.SneakyThrows; 7 | import org.springframework.http.HttpEntity; 8 | import org.springframework.http.HttpMethod; 9 | import org.springframework.util.Assert; 10 | import org.springframework.web.client.RestTemplate; 11 | 12 | /** 13 | * api resource used by admins to impersonate as someone else 14 | */ 15 | public class ImpersonateResource implements BaseRestResource, ImpersonateApi { 16 | 17 | public static final String API_IMPERSONATE = "/api/impersonate/"; 18 | protected RestTemplate restTemplate; 19 | protected String baseAuthApiUrl; 20 | 21 | public ImpersonateResource(String baseAuthApiUrl, RestTemplate restTemplate) { 22 | Assert.hasText(baseAuthApiUrl, "baseAuthApiUrl is required"); 23 | this.restTemplate = restTemplate; 24 | this.baseAuthApiUrl = baseAuthApiUrl; 25 | } 26 | 27 | public ImpersonateResource(JwtRestTemplate restTemplate) { 28 | this.restTemplate = restTemplate; 29 | this.baseAuthApiUrl = restTemplate.getTokenProvider().getBaseAuthApiUrl(); 30 | } 31 | 32 | @Override 33 | @SneakyThrows 34 | public JwtTokenBundle impersonate(String userIdOrUsername) { 35 | return restTemplate.exchange(createUriComponentsBuilder(baseAuthApiUrl) 36 | .path(API_IMPERSONATE) 37 | .path(userIdOrUsername).toUriString(), 38 | HttpMethod.GET, 39 | new HttpEntity<>(createHeaderWithLanguage()), 40 | JwtTokenBundle.class).getBody(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/util/JwtTokenBody.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | import java.time.Instant; 9 | import java.util.List; 10 | 11 | @Setter 12 | @JsonIgnoreProperties(ignoreUnknown = true) 13 | public class JwtTokenBody { 14 | 15 | /** 16 | * token creation date 17 | */ 18 | private Long iat; 19 | /** 20 | * expiration 21 | */ 22 | private Long exp; 23 | /** 24 | * username 25 | */ 26 | private String sub; 27 | 28 | @Getter 29 | @JsonProperty("user_id") 30 | private String userId; 31 | 32 | @Getter 33 | /** 34 | * roles 35 | */ 36 | private List scopes; 37 | 38 | public boolean isExpired() { 39 | if (exp != null) { 40 | return getExpiration().isBefore(Instant.now()); 41 | } 42 | return false; 43 | } 44 | 45 | public Instant getExpiration() { 46 | if (exp != null) { 47 | return Instant.ofEpochSecond(exp, 0); 48 | } 49 | return null; 50 | } 51 | 52 | public Instant getIssuedAt() { 53 | if (iat != null) { 54 | return Instant.ofEpochSecond(iat, 0); 55 | } 56 | return null; 57 | } 58 | 59 | public String getUsername() { 60 | return sub; 61 | } 62 | 63 | public boolean hasRole(String name) { 64 | return scopes != null && scopes.stream() 65 | .filter(s -> s.equalsIgnoreCase(name)) 66 | .findFirst().isPresent(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/util/JwtTokenDecoder.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.util; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | 5 | import java.util.Base64; 6 | 7 | public final class JwtTokenDecoder { 8 | 9 | public static JwtTokenBody decodeTokenBody(String token) { 10 | if (token != null) { 11 | String[] split = token.split("\\."); 12 | if (split.length == 3) { 13 | try { 14 | byte[] body = Base64.getUrlDecoder().decode(split[1]); 15 | return new ObjectMapper().readValue(body, JwtTokenBody.class); 16 | } catch (Exception e) { 17 | } 18 | } 19 | } 20 | return null; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/util/JwtTokenStore.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.util; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | import io.rocketbase.commons.exception.TokenRefreshException; 5 | 6 | import java.io.Serializable; 7 | 8 | public interface JwtTokenStore extends Serializable { 9 | 10 | boolean checkTokenNeedsRefresh(); 11 | 12 | boolean checkTokenNeedsRefresh(long seconds); 13 | 14 | void refreshToken() throws TokenRefreshException; 15 | 16 | String getHeaderName(); 17 | 18 | String getTokenHeader(); 19 | 20 | JwtTokenBundle getTokenBundle(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /commons-auth-api/src/main/java/io/rocketbase/commons/util/UsernameGenerator.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.util; 2 | 3 | import org.springframework.util.StringUtils; 4 | 5 | import java.text.Normalizer; 6 | 7 | public abstract class UsernameGenerator { 8 | 9 | private static String[][] UMLAUT_REPLACEMENTS = {{"Ä", "Ae"}, {"Ü", "Ue"}, {"Ö", "Oe"}, {"ä", "ae"}, {"ü", "ue"}, {"ö", "oe"}, {"ß", "ss"}}; 10 | 11 | public static String replaceUmlaute(String orig) { 12 | String result = Nulls.notNull(orig) + ""; 13 | for (int i = 0; i < UMLAUT_REPLACEMENTS.length; i++) { 14 | result = result.replace(UMLAUT_REPLACEMENTS[i][0], UMLAUT_REPLACEMENTS[i][1]); 15 | } 16 | return result; 17 | } 18 | 19 | public static String normalizeString(String input) { 20 | String result = Nulls.notNull(input) + ""; 21 | result = replaceUmlaute(result); 22 | result = Normalizer.normalize(result, Normalizer.Form.NFD) 23 | .replaceAll("[^\\p{ASCII}]", ""); 24 | return result.toLowerCase().replaceAll("[^a-z0-9\\.\\-\\_]*", ""); 25 | } 26 | 27 | public static String byFirstAndLastName(String firstName, String lastName) { 28 | String result = ""; 29 | if (!StringUtils.isEmpty(firstName)) { 30 | result += firstName; 31 | } 32 | if (!StringUtils.isEmpty(lastName)) { 33 | if (result.length() > 0) { 34 | result += "."; 35 | } 36 | result += lastName; 37 | } 38 | return normalizeString(result); 39 | } 40 | 41 | public static String byEmail(String email) { 42 | int atIndex = Nulls.notNull(email).lastIndexOf("@"); 43 | if (atIndex <= 0) { 44 | return null; 45 | } 46 | return normalizeString(email.substring(0, atIndex)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /commons-auth-api/src/test/java/io/rocketbase/commons/util/UsernameGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.util; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.hamcrest.MatcherAssert.assertThat; 6 | import static org.hamcrest.Matchers.is; 7 | 8 | public class UsernameGeneratorTest { 9 | 10 | @Test 11 | public void replaceUmlaute() { 12 | // given 13 | String input = "ÖlapalümäAß"; 14 | // when 15 | String result = UsernameGenerator.replaceUmlaute(input); 16 | // then 17 | assertThat(result, is("OelapaluemaeAss")); 18 | } 19 | 20 | @Test 21 | public void normalizeString() { 22 | // given 23 | String input = "ÄöüMte@e° eé?ß# +´´"; 24 | // when 25 | String result = UsernameGenerator.normalizeString(input); 26 | // then 27 | assertThat(result, is("aeoeuemteeeess")); 28 | } 29 | 30 | @Test 31 | public void byFirstAndLastName() { 32 | // given 33 | String firstName = "Ünal"; 34 | String lastName = "MöllerPütt"; 35 | // when 36 | String result = UsernameGenerator.byFirstAndLastName(firstName, lastName); 37 | // then 38 | assertThat(result, is("uenal.moellerpuett")); 39 | } 40 | 41 | @Test 42 | public void byEmail() { 43 | // given 44 | String email = "Süper-user@web.de"; 45 | // when 46 | String result = UsernameGenerator.byEmail(email); 47 | // then 48 | assertThat(result, is("sueper-user")); 49 | } 50 | } -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/adapters/AuthClientRequestFactory.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.adapters; 2 | 3 | 4 | import io.rocketbase.commons.security.CommonsAuthenticationToken; 5 | import io.rocketbase.commons.util.JwtTokenStore; 6 | import org.apache.http.client.methods.HttpUriRequest; 7 | import org.springframework.http.client.ClientHttpRequestFactory; 8 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.context.SecurityContextHolder; 11 | 12 | public class AuthClientRequestFactory extends HttpComponentsClientHttpRequestFactory implements ClientHttpRequestFactory { 13 | 14 | @Override 15 | protected void postProcessHttpRequest(HttpUriRequest request) { 16 | JwtTokenStore jwtTokenStore = getCommonsAuthenticationToken().getJwtTokenStore(); 17 | if (jwtTokenStore.checkTokenNeedsRefresh()) { 18 | jwtTokenStore.refreshToken(); 19 | } 20 | request.setHeader(jwtTokenStore.getHeaderName(), jwtTokenStore.getTokenHeader()); 21 | } 22 | 23 | protected CommonsAuthenticationToken getCommonsAuthenticationToken() { 24 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 25 | CommonsAuthenticationToken token; 26 | 27 | if (authentication == null) { 28 | throw new IllegalStateException("Cannot set authorization header because there is no authenticated principal"); 29 | } 30 | 31 | if (!CommonsAuthenticationToken.class.isAssignableFrom(authentication.getClass())) { 32 | throw new IllegalStateException( 33 | String.format( 34 | "Cannot set authorization header because Authentication is of type %s but %s is required", 35 | authentication.getClass(), CommonsAuthenticationToken.class) 36 | ); 37 | } 38 | 39 | token = (CommonsAuthenticationToken) authentication; 40 | return token; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/adapters/AuthRestTemplate.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.adapters; 2 | 3 | import io.rocketbase.commons.resource.BasicResponseErrorHandler; 4 | import org.springframework.web.client.RestOperations; 5 | import org.springframework.web.client.RestTemplate; 6 | 7 | public class AuthRestTemplate extends RestTemplate implements RestOperations { 8 | 9 | /** 10 | * use SecurityContext as source for authentications 11 | */ 12 | public AuthRestTemplate(AuthClientRequestFactory requestFactory) { 13 | super(requestFactory); 14 | init(); 15 | } 16 | 17 | /** 18 | * login user once and work with it's credentials 19 | */ 20 | public AuthRestTemplate(AuthClientLoginRequestFactory requestFactory) { 21 | super(requestFactory); 22 | init(); 23 | } 24 | 25 | /** 26 | * login user once and work with it's credentials 27 | */ 28 | public AuthRestTemplate(String baseAuthApiUrl, String username, String password) { 29 | super(new AuthClientLoginRequestFactory(baseAuthApiUrl, username, password)); 30 | init(); 31 | } 32 | 33 | protected void init() { 34 | setErrorHandler(new BasicResponseErrorHandler()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/config/EmailProperties.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | @Data 7 | @ConfigurationProperties(prefix = "auth.email") 8 | public class EmailProperties { 9 | 10 | private String subjectPrefix = "[Auth]"; 11 | private String serviceName = "commons-auth"; 12 | 13 | private EmailLogo logo; 14 | private String greetingFrom = "commons-auth"; 15 | 16 | private String supportEmail = "support@localhost"; 17 | private String fromEmail = "no-reply@localhost"; 18 | private String copyrightName = "commons-auth"; 19 | private String copyrightUrl = "https://github.com/rocketbase-io/commons-auth"; 20 | 21 | @Data 22 | public static class EmailLogo { 23 | private String src; 24 | private Integer width; 25 | private Integer height; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/config/FormsProperties.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import io.rocketbase.commons.util.UrlParts; 4 | import lombok.Data; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | 7 | @Data 8 | @ConfigurationProperties(prefix = "auth.forms") 9 | public class FormsProperties { 10 | 11 | /** 12 | * prefix for the paths of the forms-controller 13 | */ 14 | private String prefix = ""; 15 | 16 | private String title = "commons-auth"; 17 | 18 | private String logoSrc = "./assets/rocketbase.svg"; 19 | 20 | /** 21 | * quick help to configure spring security 22 | */ 23 | public String[] getFormEndpointPaths() { 24 | String prefixPath = UrlParts.ensureStartsAndEndsWithSlash(prefix); 25 | return new String[]{ 26 | prefixPath + "login", 27 | prefixPath + "logout", 28 | prefixPath + "forgot", 29 | prefixPath + "reset-password", 30 | prefixPath + "verify-email" 31 | }; 32 | } 33 | 34 | /** 35 | * quick help to configure spring security 36 | */ 37 | public String[] getInviteEndpointPaths() { 38 | String prefixPath = UrlParts.ensureStartsAndEndsWithSlash(prefix); 39 | return new String[]{ 40 | prefixPath + "invite" 41 | }; 42 | } 43 | 44 | /** 45 | * quick help to configure spring security 46 | */ 47 | public String[] getRegistrationEndpointPaths() { 48 | String prefixPath = UrlParts.ensureStartsAndEndsWithSlash(prefix); 49 | return new String[]{ 50 | prefixPath + "registration", 51 | prefixPath + "verification" 52 | }; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/config/JwtProperties.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.http.HttpHeaders; 6 | 7 | import javax.validation.constraints.NotNull; 8 | 9 | @Data 10 | @ConfigurationProperties(prefix = "auth.jwt") 11 | public class JwtProperties { 12 | 13 | 14 | private String header = HttpHeaders.AUTHORIZATION; 15 | private String tokenPrefix = "Bearer "; 16 | private String uriParam = "token"; 17 | 18 | @NotNull 19 | private String secret; 20 | 21 | /** 22 | * default 1 hour 23 | */ 24 | private long accessTokenExpiration = 60; 25 | 26 | /** 27 | * default 30 days 28 | */ 29 | private long refreshTokenExpiration = 43200; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/config/PasswordProperties.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | @Data 7 | @ConfigurationProperties(prefix = "auth.password") 8 | public class PasswordProperties { 9 | 10 | private int minLength = 8; 11 | 12 | private int maxLength = 100; 13 | 14 | private int lowercase = 1; 15 | 16 | private int uppercase = 1; 17 | 18 | private int digit = 1; 19 | 20 | /** 21 | * character of this list:
22 | * !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 23 | */ 24 | private int special = 1; 25 | } 26 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/config/RegistrationProperties.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.validation.annotation.Validated; 6 | 7 | @Data 8 | @ConfigurationProperties(prefix = "auth.registration") 9 | @Validated 10 | public class RegistrationProperties { 11 | 12 | private boolean enabled = true; 13 | 14 | /** 15 | * should use verify it's email-adress 16 | */ 17 | private boolean verification = true; 18 | 19 | /** 20 | * in minutes - default 1 day 21 | */ 22 | private long verificationExpiration = 1440; 23 | 24 | private String role = "USER"; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/config/UsernameProperties.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | @Data 7 | @ConfigurationProperties(prefix = "auth.username") 8 | public class UsernameProperties { 9 | 10 | private int minLength = 3; 11 | 12 | private int maxLength = 20; 13 | 14 | private String specialCharacters = ".-_"; 15 | } 16 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/converter/AppUserConverter.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.converter; 2 | 3 | import io.rocketbase.commons.dto.appuser.AppUserRead; 4 | import io.rocketbase.commons.model.AppUserEntity; 5 | import io.rocketbase.commons.util.RolesAuthoritiesConverter; 6 | 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.stream.Collectors; 11 | 12 | public class AppUserConverter { 13 | 14 | public static Map filterInvisibleKeys(Map keyValues) { 15 | if (keyValues == null) { 16 | return null; 17 | } 18 | Map map = new HashMap<>(); 19 | keyValues.entrySet().stream() 20 | .filter(e -> !e.getKey().startsWith("_")) 21 | .forEach(e -> map.put(e.getKey(), e.getValue())); 22 | return map; 23 | } 24 | 25 | public AppUserRead fromEntity(AppUserEntity entity) { 26 | if (entity == null) { 27 | return null; 28 | } 29 | return AppUserRead.builder() 30 | .id(entity.getId()) 31 | .username(entity.getUsername()) 32 | .firstName(entity.getFirstName()) 33 | .lastName(entity.getLastName()) 34 | .email(entity.getEmail()) 35 | .avatar(entity.getAvatar()) 36 | .roles(RolesAuthoritiesConverter.convertRoles(entity.getRoles())) 37 | .keyValues(filterInvisibleKeys(entity.getKeyValues())) 38 | .enabled(entity.isEnabled()) 39 | .created(entity.getCreated()) 40 | .lastLogin(entity.getLastLogin()) 41 | .build(); 42 | } 43 | 44 | public List fromEntities(List entities) { 45 | if (entities == null) { 46 | return null; 47 | } 48 | return entities.stream() 49 | .map(e -> fromEntity(e)) 50 | .collect(Collectors.toList()); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/converter/ValidationConverter.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.converter; 2 | 3 | import io.rocketbase.commons.dto.validation.ValidationResponse; 4 | import io.rocketbase.commons.exception.ValidationErrorCode; 5 | 6 | import java.util.HashMap; 7 | import java.util.Set; 8 | 9 | public class ValidationConverter { 10 | 11 | public static > ValidationResponse convert(Set> errors) { 12 | ValidationResponse response = new ValidationResponse<>(errors != null && errors.isEmpty(), new HashMap<>()); 13 | if (errors != null) { 14 | for (ValidationErrorCode c : errors) { 15 | response.getErrorCodes().put(c.getCode(), c.getMessage()); 16 | } 17 | } 18 | return response; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/ActiveUserChangedEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import lombok.Getter; 4 | import org.springframework.context.ApplicationEvent; 5 | 6 | /** 7 | * will get trigged when amount of ActiveUserStore is changed 8 | */ 9 | @Getter 10 | public class ActiveUserChangedEvent extends ApplicationEvent { 11 | 12 | public ActiveUserChangedEvent(Object source) { 13 | super(source); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/EmailChangeEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppUserEntity; 4 | import lombok.Getter; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | @Getter 8 | public class EmailChangeEvent extends ApplicationEvent { 9 | 10 | private final String oldEmailAddress; 11 | private final AppUserEntity appUserEntity; 12 | 13 | 14 | public EmailChangeEvent(Object source, String oldEmailAddress, AppUserEntity appUserEntity) { 15 | super(source); 16 | this.oldEmailAddress = oldEmailAddress; 17 | this.appUserEntity = appUserEntity; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/ImpersonateEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppUserToken; 4 | import lombok.Getter; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | @Getter 8 | public class ImpersonateEvent extends ApplicationEvent { 9 | 10 | private final AppUserToken requestedBy; 11 | private final AppUserToken impersonateAs; 12 | 13 | public ImpersonateEvent(Object source, AppUserToken requestedBy, AppUserToken impersonateAs) { 14 | super(source); 15 | this.requestedBy = requestedBy; 16 | this.impersonateAs = impersonateAs; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/InviteEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppInviteEntity; 4 | import io.rocketbase.commons.model.AppUserEntity; 5 | import lombok.Getter; 6 | import org.springframework.context.ApplicationEvent; 7 | 8 | import javax.annotation.Nullable; 9 | 10 | @Getter 11 | public class InviteEvent extends ApplicationEvent { 12 | 13 | private final AppInviteEntity appInviteEntity; 14 | private final InviteProcessType type; 15 | 16 | /** 17 | * only filled in case on processType confirm 18 | */ 19 | @Nullable 20 | private AppUserEntity appUserEntity; 21 | 22 | public InviteEvent(Object source, AppInviteEntity appInviteEntity, InviteProcessType type) { 23 | super(source); 24 | this.appInviteEntity = appInviteEntity; 25 | this.type = type; 26 | } 27 | 28 | public InviteEvent(Object source, AppInviteEntity appInviteEntity, AppUserEntity appUserEntity) { 29 | super(source); 30 | this.appInviteEntity = appInviteEntity; 31 | this.type = InviteProcessType.CONFIRM; 32 | this.appUserEntity = appUserEntity; 33 | } 34 | 35 | public enum InviteProcessType { 36 | CREATE, 37 | VERIFY, 38 | CONFIRM 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/LoginEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppUserEntity; 4 | import lombok.Getter; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | @Getter 8 | public class LoginEvent extends ApplicationEvent { 9 | 10 | private final AppUserEntity appUserEntity; 11 | 12 | public LoginEvent(Object source, AppUserEntity appUserEntity) { 13 | super(source); 14 | this.appUserEntity = appUserEntity; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/PasswordEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppUserEntity; 4 | import lombok.Getter; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | @Getter 8 | public class PasswordEvent extends ApplicationEvent { 9 | 10 | private final AppUserEntity appUserEntity; 11 | private final PasswordProcessType type; 12 | 13 | public PasswordEvent(Object source, AppUserEntity appUserEntity, PasswordProcessType type) { 14 | super(source); 15 | this.appUserEntity = appUserEntity; 16 | this.type = type; 17 | } 18 | 19 | public enum PasswordProcessType { 20 | REQUEST_RESET, 21 | PROCEED_RESET, 22 | CHANGED 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/RefreshTokenEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppUserEntity; 4 | import lombok.Getter; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | @Getter 8 | public class RefreshTokenEvent extends ApplicationEvent { 9 | 10 | private final AppUserEntity appUserEntity; 11 | 12 | public RefreshTokenEvent(Object source, AppUserEntity appUserEntity) { 13 | super(source); 14 | this.appUserEntity = appUserEntity; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/RegistrationEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppUserEntity; 4 | import lombok.Getter; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | @Getter 8 | public class RegistrationEvent extends ApplicationEvent { 9 | 10 | private final AppUserEntity appUserEntity; 11 | private final RegistrationProcessType type; 12 | 13 | public RegistrationEvent(Object source, AppUserEntity appUserEntity, RegistrationProcessType type) { 14 | super(source); 15 | this.appUserEntity = appUserEntity; 16 | this.type = type; 17 | } 18 | 19 | public enum RegistrationProcessType { 20 | REGISTER, 21 | VERIFIED 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/RequestMeEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppUserEntity; 4 | import lombok.Getter; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | @Getter 8 | public class RequestMeEvent extends ApplicationEvent { 9 | 10 | private final AppUserEntity appUserEntity; 11 | 12 | public RequestMeEvent(Object source, AppUserEntity appUserEntity) { 13 | super(source); 14 | this.appUserEntity = appUserEntity; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/UpdateProfileEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppUserEntity; 4 | import lombok.Getter; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | @Getter 8 | public class UpdateProfileEvent extends ApplicationEvent { 9 | 10 | private final AppUserEntity appUserEntity; 11 | 12 | public UpdateProfileEvent(Object source, AppUserEntity appUserEntity) { 13 | super(source); 14 | this.appUserEntity = appUserEntity; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/event/UsernameChangeEvent.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.event; 2 | 3 | import io.rocketbase.commons.model.AppUserEntity; 4 | import lombok.Getter; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | @Getter 8 | public class UsernameChangeEvent extends ApplicationEvent { 9 | 10 | private final String oldUsername; 11 | private final AppUserEntity appUserEntity; 12 | 13 | 14 | public UsernameChangeEvent(Object source, String oldUsername, AppUserEntity appUserEntity) { 15 | super(source); 16 | this.oldUsername = oldUsername; 17 | this.appUserEntity = appUserEntity; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/model/AppInviteEntity.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | import javax.validation.constraints.Email; 6 | import javax.validation.constraints.NotNull; 7 | import java.time.Instant; 8 | import java.util.List; 9 | 10 | public interface AppInviteEntity extends EntityWithKeyValue, HasFirstAndLastName { 11 | 12 | String getId(); 13 | 14 | void setId(String id); 15 | 16 | String getInvitor(); 17 | 18 | void setInvitor(@NotNull String invitor); 19 | 20 | String getMessage(); 21 | 22 | void setMessage(String message); 23 | 24 | String getFirstName(); 25 | 26 | void setFirstName(String firstName); 27 | 28 | String getLastName(); 29 | 30 | void setLastName(String lastName); 31 | 32 | String getEmail(); 33 | 34 | void setEmail(@NotNull @Email String email); 35 | 36 | List getRoles(); 37 | 38 | void setRoles(List roles); 39 | 40 | Instant getCreated(); 41 | 42 | Instant getExpiration(); 43 | 44 | void setExpiration(@NotNull Instant expiration); 45 | 46 | /** 47 | * fullname fallback if null use email 48 | */ 49 | @JsonIgnore 50 | default String getDisplayName() { 51 | String fullName = getFullName(); 52 | if (fullName == null) { 53 | return getEmail(); 54 | } 55 | return fullName; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/model/EntityWithKeyValue.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.model; 2 | 3 | import org.springframework.util.Assert; 4 | 5 | public interface EntityWithKeyValue extends HasKeyValue { 6 | 7 | /** 8 | * @param key max length of 50 characters
9 | * key with _ as prefix will not get displayed in REST_API 10 | * key with # as prefix will not get rendered within jwt-token but in userDto 11 | * @param value max length of 4000 characters 12 | * @return itself for fluent api 13 | */ 14 | default T addKeyValue(String key, String value) { 15 | checkKeyValue(key, value); 16 | getKeyValues().put(key, value); 17 | return (T) this; 18 | } 19 | 20 | default void removeKeyValue(String key) { 21 | getKeyValues().remove(key); 22 | } 23 | 24 | default void checkKeyValue(String key, String value) { 25 | Assert.hasLength(key, "Key must not be empty"); 26 | Assert.state(key.length() <= 50, "Key is too long - at least 50 chars"); 27 | Assert.state(key.matches("[a-zA-Z0-9_\\-\\.\\#]+"), "Allowed key chars are a-Z, 0-9 and _-.#"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/security/CommonsAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.security; 2 | 3 | import io.rocketbase.commons.model.AppUserToken; 4 | import io.rocketbase.commons.util.JwtTokenStore; 5 | import lombok.Getter; 6 | import org.springframework.security.authentication.AbstractAuthenticationToken; 7 | import org.springframework.security.core.GrantedAuthority; 8 | 9 | import java.util.Collection; 10 | 11 | public class CommonsAuthenticationToken extends AbstractAuthenticationToken { 12 | 13 | @Getter 14 | private final CommonsPrincipal principal; 15 | 16 | @Getter 17 | private final JwtTokenStore jwtTokenStore; 18 | 19 | public CommonsAuthenticationToken(Collection authorities, AppUserToken appUserToken, JwtTokenStore jwtTokenStore) { 20 | super(authorities); 21 | this.principal = new CommonsPrincipal(appUserToken); 22 | this.jwtTokenStore = jwtTokenStore; 23 | } 24 | 25 | @Override 26 | public Object getCredentials() { 27 | return jwtTokenStore.getTokenBundle(); 28 | } 29 | 30 | /** 31 | * shortcut for username of token 32 | */ 33 | public String getUsername() { 34 | return principal.getUsername(); 35 | } 36 | 37 | /** 38 | * shortcut for id of token 39 | */ 40 | public String getId() { 41 | return principal.getId(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/security/CustomAuthoritiesProvider.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.security; 2 | 3 | import io.rocketbase.commons.model.AppUserToken; 4 | import org.springframework.security.core.GrantedAuthority; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | import java.util.Collection; 8 | 9 | /** 10 | * provide extra authorities apart from the general user-roles stored in db 11 | */ 12 | public interface CustomAuthoritiesProvider { 13 | 14 | /** 15 | * will get injected in case of jwt-token creation
16 | * that means they are also present in case of SecurityContext
17 | * this should be considered for nearly static authorities that don't switch during a session 18 | * 19 | * @return a not nullable list of extra authorities / could also be an empty list 20 | */ 21 | Collection getExtraTokenAuthorities(AppUserToken user); 22 | 23 | /** 24 | * will get injected in case of SecurityContext initialization
25 | * you will find it in the security filter {@link io.rocketbase.commons.filter.JwtAuthenticationTokenFilter}
26 | * this should be considered for nearly dynamic authorities
27 | * keep in mind that also the extra token authorities will be present already 28 | * 29 | * @return a not nullable list of extra authorities / could also be an empty list 30 | */ 31 | Collection getExtraSecurityContextAuthorities(AppUserToken user, HttpServletRequest request); 32 | } 33 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/security/EmptyCustomAuthoritiesProvider.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.security; 2 | 3 | import io.rocketbase.commons.model.AppUserToken; 4 | import org.springframework.security.core.GrantedAuthority; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | 10 | /** 11 | * default implementation of {@link CustomAuthoritiesProvider} 12 | */ 13 | public class EmptyCustomAuthoritiesProvider implements CustomAuthoritiesProvider { 14 | 15 | @Override 16 | public Collection getExtraTokenAuthorities(AppUserToken user) { 17 | return Collections.emptyList(); 18 | } 19 | 20 | @Override 21 | public Collection getExtraSecurityContextAuthorities(AppUserToken user, HttpServletRequest request) { 22 | return Collections.emptyList(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/AppInvitePersistenceService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service; 2 | 3 | import io.rocketbase.commons.dto.appinvite.QueryAppInvite; 4 | import io.rocketbase.commons.model.AppInviteEntity; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | import java.util.Optional; 9 | 10 | public interface AppInvitePersistenceService { 11 | 12 | Page findAll(QueryAppInvite query, Pageable pageable); 13 | 14 | S save(S entity); 15 | 16 | Optional findById(String id); 17 | 18 | long count(); 19 | 20 | void delete(S entity); 21 | 22 | void deleteAll(); 23 | 24 | S initNewInstance(); 25 | 26 | long deleteExpired(); 27 | } 28 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/AppUserPersistenceService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service; 2 | 3 | import io.rocketbase.commons.dto.appuser.QueryAppUser; 4 | import io.rocketbase.commons.model.AppUserEntity; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | import java.util.Optional; 9 | 10 | public interface AppUserPersistenceService { 11 | 12 | Optional findByUsername(String username); 13 | 14 | Optional findByEmail(String email); 15 | 16 | Page findAll(QueryAppUser query, Pageable pageable); 17 | 18 | S save(S entity); 19 | 20 | Optional findById(String id); 21 | 22 | long count(); 23 | 24 | void delete(S entity); 25 | 26 | void deleteAll(); 27 | 28 | S initNewInstance(); 29 | } 30 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/JwtTokenStoreProvider.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | import io.rocketbase.commons.util.JwtTokenStore; 5 | 6 | public interface JwtTokenStoreProvider { 7 | 8 | JwtTokenStore getInstance(JwtTokenBundle tokenBundle); 9 | } 10 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/KeyGenerator.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service; 2 | 3 | import java.security.SecureRandom; 4 | 5 | public final class KeyGenerator { 6 | 7 | private static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 8 | private static final String SPECIAL_SIGN = "!#$%&()*+,-./:;<=>?@[]^_`{|}~"; 9 | private static final String ALPHABET_WITH_SPECIAL = ALPHABET + SPECIAL_SIGN; 10 | private static SecureRandom RANDOM = new SecureRandom(); 11 | 12 | /** 13 | * random string with alphabet of 0-9 + a-z (lower/upper) 14 | * 15 | * @param length of string 16 | * @return random string 17 | */ 18 | public static String random(int length) { 19 | StringBuilder sb = new StringBuilder(length); 20 | for (int i = 0; i < length; i++) 21 | sb.append(ALPHABET.charAt(RANDOM.nextInt(ALPHABET.length()))); 22 | return sb.toString(); 23 | } 24 | 25 | /** 26 | * random string with alphabet of 0-9 + a-z (lower/upper)
27 | * plus special sings of "!#$%&()*+,-./:;<=>?@[]^_`{|}~" 28 | * 29 | * @param length of string 30 | * @return random string 31 | */ 32 | public static String randomWithSpecialSigns(int length) { 33 | StringBuilder sb = new StringBuilder(length); 34 | for (int i = 0; i < length; i++) 35 | sb.append(ALPHABET_WITH_SPECIAL.charAt(RANDOM.nextInt(ALPHABET_WITH_SPECIAL.length()))); 36 | return sb.toString(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/ValidationUserLookupService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service; 2 | 3 | import io.rocketbase.commons.model.AppUserEntity; 4 | import io.rocketbase.commons.model.AppUserToken; 5 | 6 | import java.util.Optional; 7 | 8 | public interface ValidationUserLookupService { 9 | 10 | AppUserToken getByUsername(String username); 11 | 12 | Optional findByEmail(String email); 13 | } 14 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/avatar/AvatarService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.avatar; 2 | 3 | public interface AvatarService { 4 | 5 | String getAvatar(String email); 6 | 7 | boolean isEnabled(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/avatar/GravatarService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.avatar; 2 | 3 | import io.rocketbase.commons.config.GravatarProperties; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.SneakyThrows; 6 | import org.springframework.web.util.UriComponentsBuilder; 7 | 8 | import javax.xml.bind.DatatypeConverter; 9 | import java.security.MessageDigest; 10 | 11 | @RequiredArgsConstructor 12 | public class GravatarService implements AvatarService { 13 | 14 | final GravatarProperties gravatarProperties; 15 | 16 | @Override 17 | public String getAvatar(String email) { 18 | if (email == null) { 19 | return null; 20 | } 21 | UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString("https://www.gravatar.com/avatar/"); 22 | uriBuilder.path(md5(email.toLowerCase())); 23 | uriBuilder.path(".jpg"); 24 | uriBuilder.queryParam("s", gravatarProperties.getSize()); 25 | uriBuilder.queryParam("d", gravatarProperties.getImage().getUrlParam()); 26 | if (gravatarProperties.getRating() != null) { 27 | uriBuilder.queryParam("r", gravatarProperties.getRating().getUrlParam()); 28 | } 29 | return uriBuilder.toUriString(); 30 | } 31 | 32 | @SneakyThrows 33 | private String md5(String text) { 34 | MessageDigest md = MessageDigest.getInstance("MD5"); 35 | md.update((text == null ? "" : text).getBytes()); 36 | return DatatypeConverter.printHexBinary(md.digest()).toLowerCase(); 37 | } 38 | 39 | @Override 40 | public boolean isEnabled() { 41 | return gravatarProperties.isEnabled(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/email/AuthEmailService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.email; 2 | 3 | import io.rocketbase.commons.model.AppInviteEntity; 4 | import io.rocketbase.commons.model.AppUserReference; 5 | 6 | public interface AuthEmailService { 7 | 8 | void sentRegistrationEmail(AppUserReference user, String verificationUrl); 9 | 10 | void sentForgotPasswordEmail(AppUserReference user, String verificationUrl); 11 | 12 | void sentInviteEmail(AppInviteEntity invite, String verificationUrl); 13 | 14 | void sentChangeEmailAddressEmail(AppUserReference user, String newEmailAddress, String verificationUrl); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/email/EmailAddress.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.email; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | 6 | import javax.annotation.Nullable; 7 | import javax.validation.ConstraintViolation; 8 | import javax.validation.Validation; 9 | import javax.validation.ValidatorFactory; 10 | import javax.validation.constraints.Email; 11 | import javax.validation.constraints.NotNull; 12 | import java.util.Set; 13 | 14 | @Getter 15 | @RequiredArgsConstructor 16 | public class EmailAddress { 17 | 18 | @NotNull 19 | @Email 20 | private final String email; 21 | 22 | @Nullable 23 | private final String name; 24 | 25 | public EmailAddress(String email) { 26 | this.email = email; 27 | this.name = null; 28 | } 29 | 30 | public boolean isValid() { 31 | ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 32 | Set> validate = factory.getValidator().validate(this); 33 | return validate == null || validate.isEmpty(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/email/EmailLogSender.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.email; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | @Slf4j 6 | public class EmailLogSender implements EmailSender { 7 | 8 | @Override 9 | public void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from) { 10 | log.warn("sentEmail to: {}, subject: {}", to.getEmail(), subject); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/email/EmailSender.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.email; 2 | 3 | public interface EmailSender { 4 | 5 | void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from); 6 | } 7 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/service/user/ActiveUserStore.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.user; 2 | 3 | import io.rocketbase.commons.model.AppUserToken; 4 | 5 | import java.util.Set; 6 | 7 | public interface ActiveUserStore { 8 | void addUser(AppUserToken user); 9 | 10 | void clear(); 11 | 12 | long getUserCount(); 13 | 14 | Set getUserIds(); 15 | } 16 | -------------------------------------------------------------------------------- /commons-auth-core/src/main/java/io/rocketbase/commons/util/RolesAuthoritiesConverter.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.util; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | 12 | public final class RolesAuthoritiesConverter { 13 | 14 | /** 15 | * converts a list of roles into a collection of GrantedAuthority 16 | * 17 | * @return never null 18 | */ 19 | public static Collection convert(List roles) { 20 | return roles != null ? 21 | roles.stream() 22 | .map(r -> new SimpleGrantedAuthority(String.format("ROLE_%s", r.replaceAll("^ROLE_", "")))) 23 | .collect(Collectors.toList()) : 24 | Collections.emptyList(); 25 | } 26 | 27 | /** 28 | * converts a collection of authorities into a list of roles 29 | * 30 | * @return never null 31 | */ 32 | public static List convertToDtos(Collection authorities) { 33 | return authorities != null ? 34 | new ArrayList<>(authorities.stream() 35 | .filter(r -> r.getAuthority() != null) 36 | .map(r -> r.getAuthority()) 37 | .collect(Collectors.toSet())) : 38 | Collections.emptyList(); 39 | } 40 | 41 | /** 42 | * converts a collection of roles into a list of roles 43 | * 44 | * @return never null 45 | */ 46 | public static List convertRoles(List roles) { 47 | return roles != null ? 48 | new ArrayList<>(roles.stream() 49 | .map(r -> String.format("ROLE_%s", r.replaceAll("^ROLE_", ""))) 50 | .collect(Collectors.toSet())) : 51 | Collections.emptyList(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /commons-auth-core/src/test/java/io/rocketbase/commons/service/GravatarServiceTest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service; 2 | 3 | import io.rocketbase.commons.config.GravatarProperties; 4 | import io.rocketbase.commons.service.avatar.GravatarService; 5 | import org.junit.Test; 6 | 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | import static org.hamcrest.Matchers.*; 9 | 10 | public class GravatarServiceTest { 11 | 12 | @Test 13 | public void getAvatar() { 14 | // given 15 | String email = "marten@rocketbase.io"; 16 | 17 | // when 18 | String imageUrl = new GravatarService(getGravatarConfiguration()).getAvatar(email); 19 | 20 | // then 21 | assertThat(imageUrl, notNullValue()); 22 | assertThat(imageUrl, equalTo("https://www.gravatar.com/avatar/fc40e22b7bcd7230b49c34eb113d5dbc.jpg?s=160&d=robohash")); 23 | } 24 | 25 | @Test 26 | public void nullAvatar() { 27 | // given 28 | String email = null; 29 | 30 | // when 31 | String imageUrl = new GravatarService(getGravatarConfiguration()).getAvatar(email); 32 | 33 | // then 34 | assertThat(imageUrl, nullValue()); 35 | } 36 | 37 | private GravatarProperties getGravatarConfiguration() { 38 | GravatarProperties gravatarProperties = new GravatarProperties(); 39 | gravatarProperties.setSize(160); 40 | gravatarProperties.setImage(GravatarProperties.DefaultImage.ROBOHASH); 41 | return gravatarProperties; 42 | } 43 | } -------------------------------------------------------------------------------- /commons-auth-core/src/test/java/io/rocketbase/commons/service/user/ActiveUserStoreLocalCacheTest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.user; 2 | 3 | import io.rocketbase.commons.model.SimpleAppUserToken; 4 | import org.junit.Test; 5 | import org.springframework.context.ApplicationEventPublisher; 6 | 7 | import java.util.Arrays; 8 | 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.equalTo; 11 | 12 | public class ActiveUserStoreLocalCacheTest { 13 | 14 | @Test 15 | public void shouldRemoveInvalided() throws Exception { 16 | // given 17 | ActiveUserStoreLocalCache activeUserStore = new ActiveUserStoreLocalCache(150); 18 | activeUserStore.applicationEventPublisher = new ApplicationEventPublisher() { 19 | @Override 20 | public void publishEvent(Object event) { 21 | 22 | } 23 | }; 24 | // when 25 | activeUserStore.addUser(new SimpleAppUserToken("1", "user-1", Arrays.asList("TEST"))); 26 | activeUserStore.addUser(new SimpleAppUserToken("2", "user-2", Arrays.asList("TEST"))); 27 | 28 | // then 29 | assertThat(activeUserStore.getUserCount(), equalTo(2L)); 30 | 31 | // when 32 | Thread.sleep(200); 33 | activeUserStore.addUser(new SimpleAppUserToken("1", "user-1", Arrays.asList("TEST"))); 34 | assertThat(activeUserStore.getUserCount(), equalTo(1L)); 35 | 36 | // when 37 | Thread.sleep(200); 38 | assertThat(activeUserStore.getUserCount(), equalTo(0L)); 39 | } 40 | } -------------------------------------------------------------------------------- /commons-auth-core/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | io.rocketbase: TRACE 4 | 5 | # auth configuration 6 | auth: 7 | jwt: 8 | secret: 'P0UoSCtNYlBlU2hWbVlxM3Q2dzl6JEMmRilKQE5jUmZUalduWnI0dTd4IUElRCpHLUthUGRTZ1ZrWHAyczV2OA==' 9 | user-cache-time: 0 -------------------------------------------------------------------------------- /commons-auth-email-postmark/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | commons-auth 7 | io.rocketbase.commons 8 | LATEST-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | commons-auth-email-postmark 13 | 14 | 15 | 16 | io.rocketbase.commons 17 | commons-auth-core 18 | ${project.version} 19 | 20 | 21 | io.rocketbase.mail 22 | postmark-spring 23 | ${postmark-spring.version} 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /commons-auth-email-postmark/src/main/java/io/rocketbase/commons/config/AuthEmailPostmarkAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import io.rocketbase.commons.service.email.EmailPostmarkSender; 4 | import io.rocketbase.commons.service.email.EmailSender; 5 | import io.rocketbase.mail.PostmarkClient; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Configuration 12 | @RequiredArgsConstructor 13 | public class AuthEmailPostmarkAutoConfiguration { 14 | 15 | @Bean 16 | public EmailSender emailSender(@Autowired PostmarkClient postmarkClient) { 17 | return new EmailPostmarkSender(postmarkClient); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /commons-auth-email-postmark/src/main/java/io/rocketbase/commons/service/email/EmailPostmarkSender.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.email; 2 | 3 | import io.rocketbase.mail.PostmarkClient; 4 | import io.rocketbase.mail.dto.Message; 5 | import io.rocketbase.mail.dto.MessageResponse; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.SneakyThrows; 8 | 9 | @RequiredArgsConstructor 10 | public class EmailPostmarkSender implements EmailSender { 11 | 12 | private final PostmarkClient postmarkClient; 13 | 14 | @SneakyThrows 15 | @Override 16 | public void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from) { 17 | Message message = new Message(); 18 | message.setFrom(convert(from)); 19 | message.setTo(convert(to)); 20 | message.setSubject(subject); 21 | message.setHtmlBody(html); 22 | message.setTextBody(text); 23 | 24 | MessageResponse response = postmarkClient.deliverMessage(message); 25 | } 26 | 27 | protected io.rocketbase.mail.dto.EmailAddress convert(EmailAddress mail) { 28 | return new io.rocketbase.mail.dto.EmailAddress(mail.getEmail(), mail.getName()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /commons-auth-email-postmark/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | io.rocketbase.commons.config.AuthEmailPostmarkAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-email-postmark/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.rocketbase.commons.config.AuthEmailPostmarkAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-email-smtp/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | commons-auth 7 | io.rocketbase.commons 8 | LATEST-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | commons-auth-email-smtp 13 | 14 | 15 | 16 | io.rocketbase.commons 17 | commons-auth-core 18 | ${project.version} 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-mail 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-autoconfigure 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /commons-auth-email-smtp/src/main/java/io/rocketbase/commons/config/AuthEmailSmtpAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import io.rocketbase.commons.service.email.EmailSender; 4 | import io.rocketbase.commons.service.email.EmailSmtpSender; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.mail.javamail.JavaMailSender; 10 | 11 | @Configuration 12 | @RequiredArgsConstructor 13 | public class AuthEmailSmtpAutoConfiguration { 14 | 15 | @Bean 16 | public EmailSender emailSender(@Autowired JavaMailSender javaMailSender) { 17 | return new EmailSmtpSender(javaMailSender); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /commons-auth-email-smtp/src/main/java/io/rocketbase/commons/service/email/EmailSmtpSender.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.email; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import lombok.SneakyThrows; 5 | import org.springframework.mail.javamail.JavaMailSender; 6 | import org.springframework.mail.javamail.MimeMessageHelper; 7 | 8 | import javax.mail.internet.InternetAddress; 9 | import javax.mail.internet.MimeMessage; 10 | import java.nio.charset.StandardCharsets; 11 | 12 | @RequiredArgsConstructor 13 | public class EmailSmtpSender implements EmailSender { 14 | 15 | private final JavaMailSender emailSender; 16 | 17 | @SneakyThrows 18 | @Override 19 | public void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from) { 20 | MimeMessage message = emailSender.createMimeMessage(); 21 | MimeMessageHelper helper = new MimeMessageHelper(message, 22 | MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED, 23 | StandardCharsets.UTF_8.name()); 24 | helper.setTo(convert(to)); 25 | helper.setSubject(subject); 26 | helper.setText(text, html); 27 | helper.setFrom(convert(from)); 28 | emailSender.send(message); 29 | } 30 | 31 | @SneakyThrows 32 | protected InternetAddress convert(EmailAddress email) { 33 | return new InternetAddress(email.getEmail(), email.getName()); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /commons-auth-email-smtp/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | io.rocketbase.commons.config.AuthEmailSmtpAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-email-smtp/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.rocketbase.commons.config.AuthEmailSmtpAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-forms/src/main/java/io/rocketbase/commons/controller/AbstractFormsController.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller; 2 | 3 | import io.rocketbase.commons.config.FormsProperties; 4 | import io.rocketbase.commons.config.RegistrationProperties; 5 | import lombok.Getter; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.ModelAttribute; 8 | 9 | public abstract class AbstractFormsController { 10 | 11 | @Getter 12 | private final FormsProperties formsProperties; 13 | @Getter 14 | private final RegistrationProperties registrationProperties; 15 | 16 | public AbstractFormsController(FormsProperties formsProperties, RegistrationProperties registrationProperties) { 17 | this.formsProperties = formsProperties; 18 | this.registrationProperties = registrationProperties; 19 | } 20 | 21 | @ModelAttribute 22 | public void populateDefaults(Model model) { 23 | model.addAttribute("title", formsProperties.getTitle()); 24 | model.addAttribute("logoSrc", formsProperties.getLogoSrc()); 25 | model.addAttribute("registrationEnabled", registrationProperties.isEnabled()); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /commons-auth-forms/src/main/java/io/rocketbase/commons/controller/VerifyChangeFormsController.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller; 2 | 3 | import io.rocketbase.commons.api.AuthenticationApi; 4 | import io.rocketbase.commons.config.FormsProperties; 5 | import io.rocketbase.commons.config.RegistrationProperties; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.Model; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestParam; 11 | 12 | @Slf4j 13 | @Controller 14 | public class VerifyChangeFormsController extends AbstractFormsController { 15 | 16 | private final AuthenticationApi authenticationApi; 17 | 18 | public VerifyChangeFormsController(FormsProperties formsProperties, RegistrationProperties registrationProperties, AuthenticationApi authenticationApi) { 19 | super(formsProperties, registrationProperties); 20 | this.authenticationApi = authenticationApi; 21 | } 22 | 23 | @GetMapping("${auth.forms.prefix:}/verify-email") 24 | public String verify(@RequestParam(value = "verification", required = false) String verification, Model model) { 25 | try { 26 | authenticationApi.verifyEmail(verification); 27 | model.addAttribute("valid", true); 28 | } catch (Exception e) { 29 | model.addAttribute("valid", false); 30 | } 31 | return "email-change-success"; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /commons-auth-forms/src/main/resources/META-INF/resources/assets/commons-auth.css: -------------------------------------------------------------------------------- 1 | @import url("https://cdnjs.cloudflare.com/ajax/libs/bulma/1.0.2/css/bulma.min.css"); 2 | @import url("https://fonts.googleapis.com/css?family=Open+Sans:300,700&display=swap"); 3 | 4 | html, body { 5 | font-family: 'Open Sans', serif; 6 | font-size: 14px; 7 | font-weight: 300; 8 | } 9 | 10 | .hero { 11 | background: #fafafa; 12 | -webkit-box-shadow: none; 13 | box-shadow: none; 14 | } 15 | 16 | .box { 17 | margin-top: 5rem; 18 | } 19 | 20 | .avatar { 21 | margin: -70px auto 20px auto; 22 | padding: 7px; 23 | background: #fff; 24 | width: 142px; 25 | height: 142px; 26 | border-radius: 50%; 27 | -webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1); 28 | box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1); 29 | } 30 | 31 | input { 32 | font-weight: 300; 33 | } 34 | 35 | p { 36 | font-weight: 700; 37 | } 38 | p.light { 39 | font-weight: 300; 40 | } -------------------------------------------------------------------------------- /commons-auth-forms/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | io.rocketbase.commons.config.AuthFormAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-forms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.rocketbase.commons.config.AuthFormAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-forms/src/main/resources/templates/email-change-success.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 |
17 |
18 |
19 |
20 |
21 | 22 |
23 | 24 | 25 |
26 |
27 |

Successfully changed email-adress *Yeah*

28 |

Your old email-adress will not get used any longer.

29 |
30 |
31 | 32 |
33 |
34 | Verification is expired please request a new email-change to get a valid link! 35 |
36 |
37 | 38 |
39 |

40 | Login 41 |

42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /commons-auth-forms/src/main/resources/templates/forgot-submitted.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 |
22 | 23 |
24 |
Successfully requested password reset
25 |
26 | 27 |
28 | You need to check your mailbox. Via the link you can change your password within X minutes. 29 |
30 |
31 |

32 | Login 33 |

34 |
35 |
36 |
37 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /commons-auth-forms/src/main/resources/templates/invite-success.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 |
22 | 23 |

Successfully created account *Yeah*

24 |
25 | You can now use the application with your account username. 26 |
27 |
28 |

29 | Login 30 |

31 |
32 |
33 |
34 |
35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /commons-auth-forms/src/main/resources/templates/registration-success.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 |
22 | 23 |

Successfully registered *Yeah*

24 |
25 | You need to verify your email. Please check your mailbox! Via the link you can confirm your registration within X minutes. 26 |
27 |
28 | You can now use the application. 29 |
30 |
31 |

32 | Login 33 |

34 |
35 |
36 |
37 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /commons-auth-forms/src/main/resources/templates/registration-verification.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 |
22 | 23 |
24 |

Successfully verified *Yeah*

25 |

You can start using the app.

26 |
27 |
28 |

Could not verify your registration.

29 |

Please retry or contact the adminstrator./

30 |
31 |
32 |

33 | Login 34 |

35 |
36 |
37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /commons-auth-forms/src/main/resources/templates/reset-password-success.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 |
22 | 23 | 24 |
25 |
Successfully changed password *Yeah*
26 |
27 | 28 |
29 | You can now login to the application again. 30 |
31 |
32 |

33 | Login 34 |

35 |
36 |
37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /commons-auth-jpa/src/main/java/io/rocketbase/commons/config/AuthJpaAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import io.rocketbase.commons.model.AppInviteJpaEntity; 4 | import io.rocketbase.commons.model.AppUserJpaEntity; 5 | import io.rocketbase.commons.repository.AppInviteJpaRepository; 6 | import io.rocketbase.commons.repository.AppUserJpaRepository; 7 | import io.rocketbase.commons.service.AppInviteJpaServiceImpl; 8 | import io.rocketbase.commons.service.AppInvitePersistenceService; 9 | import io.rocketbase.commons.service.AppUserJpaServiceImpl; 10 | import io.rocketbase.commons.service.AppUserPersistenceService; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.autoconfigure.AutoConfigureBefore; 13 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 14 | import org.springframework.context.annotation.Bean; 15 | import org.springframework.context.annotation.Configuration; 16 | 17 | @Configuration 18 | @AutoConfigureBefore(AuthServiceAutoConfiguration.class) 19 | public class AuthJpaAutoConfiguration { 20 | 21 | @Bean 22 | @ConditionalOnMissingBean 23 | public AppUserPersistenceService appUserPersistenceService(@Autowired AppUserJpaRepository appUserJpaRepository) { 24 | return new AppUserJpaServiceImpl(appUserJpaRepository); 25 | } 26 | 27 | @Bean 28 | @ConditionalOnMissingBean 29 | public AppInvitePersistenceService appInvitePersistenceService(@Autowired AppInviteJpaRepository appInviteJpaRepository) { 30 | return new AppInviteJpaServiceImpl(appInviteJpaRepository); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /commons-auth-jpa/src/main/java/io/rocketbase/commons/model/AppInviteJpaEntity.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.model; 2 | 3 | import io.rocketbase.commons.model.converter.StringListConverter; 4 | import lombok.*; 5 | import org.springframework.data.annotation.CreatedDate; 6 | 7 | import javax.persistence.*; 8 | import java.time.Instant; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | 14 | @Entity 15 | @Table(name = "co_invite") 16 | @Data 17 | @Builder 18 | @AllArgsConstructor 19 | @NoArgsConstructor 20 | @EqualsAndHashCode(of = {"id"}) 21 | public class AppInviteJpaEntity implements AppInviteEntity { 22 | 23 | @Id 24 | @Column(length = 36, nullable = false) 25 | private String id; 26 | 27 | private String invitor; 28 | 29 | @Column(length = 4000) 30 | private String message; 31 | 32 | private String firstName; 33 | 34 | private String lastName; 35 | 36 | private String email; 37 | 38 | @Column(name = "roles") 39 | @Convert(converter = StringListConverter.class) 40 | private List roles; 41 | 42 | @ElementCollection 43 | @CollectionTable( 44 | name = "co_invite_keyvalue", 45 | joinColumns = @JoinColumn(name = "invite_id"), 46 | uniqueConstraints = @UniqueConstraint(name = "uk_invite_keyvalue", columnNames = {"invite_id", "field_key"}), 47 | indexes = @Index(name = "idx_invite_keyvalue", columnList = "invite_id") 48 | ) 49 | @MapKeyColumn(name = "field_key", length = 50) 50 | @Column(name = "field_value", nullable = false) 51 | @Builder.Default 52 | private Map keyValueMap = new HashMap<>(); 53 | 54 | @CreatedDate 55 | @Column(nullable = false) 56 | private Instant created; 57 | 58 | @Column(nullable = false) 59 | private Instant expiration; 60 | 61 | @Override 62 | public Map getKeyValues() { 63 | return keyValueMap; 64 | } 65 | 66 | @Override 67 | public void setKeyValues(Map map) { 68 | this.keyValueMap = map; 69 | } 70 | 71 | public AppInviteJpaEntity(String id) { 72 | this.id = id; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /commons-auth-jpa/src/main/java/io/rocketbase/commons/model/converter/StringListConverter.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.model.converter; 2 | 3 | import com.google.common.base.Joiner; 4 | import com.google.common.base.Splitter; 5 | import com.google.common.collect.Lists; 6 | import org.springframework.util.StringUtils; 7 | 8 | import javax.persistence.AttributeConverter; 9 | import javax.persistence.Convert; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | @Convert 14 | public class StringListConverter implements AttributeConverter, String> { 15 | 16 | @Override 17 | public String convertToDatabaseColumn(List attribute) { 18 | String result = null; 19 | if (attribute != null) { 20 | result = Joiner.on(";").join(attribute); 21 | } 22 | return result; 23 | } 24 | 25 | @Override 26 | public List convertToEntityAttribute(String dbData) { 27 | List result = new ArrayList<>(); 28 | if (!StringUtils.isEmpty(dbData)) { 29 | result = Lists.newArrayList(Splitter.on(";").split(dbData)); 30 | } 31 | return result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /commons-auth-jpa/src/main/java/io/rocketbase/commons/repository/AppInviteJpaRepository.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.repository; 2 | 3 | import io.rocketbase.commons.model.AppInviteJpaEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | import org.springframework.data.jpa.repository.Query; 8 | import org.springframework.data.repository.PagingAndSortingRepository; 9 | import org.springframework.data.repository.query.Param; 10 | import org.springframework.data.repository.query.QueryByExampleExecutor; 11 | 12 | import java.util.Optional; 13 | 14 | public interface AppInviteJpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor, JpaSpecificationExecutor { 15 | 16 | @Query("select a from AppInviteJpaEntity a left join fetch a.keyValueMap where a.id = :id") 17 | Optional findById(@Param("id") String id); 18 | 19 | @Query(value = "select a from AppInviteJpaEntity a left join fetch a.keyValueMap", 20 | countQuery = "select count(a) from AppInviteJpaEntity a") 21 | Page findAll(Pageable pageable); 22 | } 23 | -------------------------------------------------------------------------------- /commons-auth-jpa/src/main/java/io/rocketbase/commons/repository/AppUserJpaRepository.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.repository; 2 | 3 | import io.rocketbase.commons.model.AppUserJpaEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | import org.springframework.data.jpa.repository.Query; 8 | import org.springframework.data.repository.PagingAndSortingRepository; 9 | import org.springframework.data.repository.query.Param; 10 | import org.springframework.data.repository.query.QueryByExampleExecutor; 11 | 12 | import java.util.Optional; 13 | 14 | public interface AppUserJpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor, JpaSpecificationExecutor { 15 | 16 | @Query("select a from AppUserJpaEntity a left join fetch a.keyValueMap left join fetch a.roles where a.id = :id") 17 | Optional findById(@Param("id") String id); 18 | 19 | @Query("select a from AppUserJpaEntity a left join fetch a.keyValueMap left join fetch a.roles where a.username = :username") 20 | Optional findByUsername(@Param("username") String username); 21 | 22 | @Query("select a from AppUserJpaEntity a left join fetch a.keyValueMap left join fetch a.roles where a.email = :email") 23 | Optional findByEmail(@Param("email") String email); 24 | 25 | @Query(value = "select a from AppUserJpaEntity a left join fetch a.keyValueMap left join fetch a.roles", 26 | countQuery = "select count(a) from AppUserJpaEntity a") 27 | Page findAll(Pageable pageable); 28 | } 29 | -------------------------------------------------------------------------------- /commons-auth-jpa/src/main/java/io/rocketbase/commons/service/PredicateHelper.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service; 2 | 3 | import org.springframework.util.StringUtils; 4 | 5 | import javax.persistence.criteria.CriteriaBuilder; 6 | import javax.persistence.criteria.Predicate; 7 | import javax.persistence.criteria.Root; 8 | import java.util.List; 9 | 10 | public interface PredicateHelper { 11 | 12 | default String buildLikeString(String value) { 13 | if (value.contains("*") || value.contains("%")) { 14 | return value.trim().toLowerCase().replace("*", "%"); 15 | } 16 | return "%" + value.trim().toLowerCase() + "%"; 17 | } 18 | 19 | default void addToListIfNotEmpty(List list, String value, String path, Root root, CriteriaBuilder cb) { 20 | if (!StringUtils.isEmpty(value)) { 21 | list.add(cb.like(cb.lower(root.get(path)), buildLikeString(value))); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /commons-auth-jpa/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | io.rocketbase.commons.config.AuthJpaAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-jpa/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.rocketbase.commons.config.AuthJpaAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-jpa/src/test/java/io/rocketbase/commons/Application.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | 10 | public static void main(String[] args) throws Exception { 11 | SpringApplication.run(Application.class, args); 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /commons-auth-jpa/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | driver-class-name: org.h2.Driver 4 | jdbc-url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 5 | username: sa 6 | password: sa 7 | 8 | main: 9 | allow-circular-references: true 10 | 11 | hibernate: 12 | dialect: org.hibernate.dialect.H2Dialect 13 | hbm2ddl: 14 | auto: create-drop 15 | show_sql: true 16 | 17 | logging: 18 | level: 19 | io.rocketbase: DEBUG 20 | org.hibernate: 21 | SQL: TRACE 22 | type.descriptor:.sql.BasicBinder: TRACE 23 | -------------------------------------------------------------------------------- /commons-auth-mongo/src/main/java/io/rocketbase/commons/config/AuthMongoAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.config; 2 | 3 | import io.rocketbase.commons.model.AppInviteMongoEntity; 4 | import io.rocketbase.commons.model.AppUserMongoEntity; 5 | import io.rocketbase.commons.service.AppInviteMongoServiceImpl; 6 | import io.rocketbase.commons.service.AppInvitePersistenceService; 7 | import io.rocketbase.commons.service.AppUserMongoServiceImpl; 8 | import io.rocketbase.commons.service.AppUserPersistenceService; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.autoconfigure.AutoConfigureBefore; 11 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.data.mongodb.core.MongoTemplate; 15 | 16 | @Configuration 17 | @AutoConfigureBefore(AuthServiceAutoConfiguration.class) 18 | public class AuthMongoAutoConfiguration { 19 | 20 | @Bean 21 | @ConditionalOnMissingBean 22 | public AppUserPersistenceService appUserPersistenceService(@Autowired MongoTemplate mongoTemplate) { 23 | return new AppUserMongoServiceImpl(mongoTemplate); 24 | } 25 | 26 | @Bean 27 | @ConditionalOnMissingBean 28 | public AppInvitePersistenceService appInvitePersistenceService(@Autowired MongoTemplate mongoTemplate) { 29 | return new AppInviteMongoServiceImpl(mongoTemplate); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /commons-auth-mongo/src/main/java/io/rocketbase/commons/model/AppInviteMongoEntity.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.model; 2 | 3 | import lombok.*; 4 | import org.springframework.data.annotation.CreatedDate; 5 | import org.springframework.data.annotation.Id; 6 | import org.springframework.data.mongodb.core.index.Indexed; 7 | import org.springframework.data.mongodb.core.mapping.Document; 8 | 9 | import javax.validation.constraints.Email; 10 | import javax.validation.constraints.NotNull; 11 | import java.time.Instant; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | 17 | @Document(collection = "invite") 18 | @Data 19 | @Builder 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @EqualsAndHashCode(of = {"id"}) 23 | public class AppInviteMongoEntity implements AppInviteEntity { 24 | 25 | @Id 26 | private String id; 27 | 28 | @Indexed 29 | private String invitor; 30 | 31 | private String message; 32 | 33 | private String firstName; 34 | 35 | private String lastName; 36 | 37 | @NotNull 38 | @Email 39 | private String email; 40 | 41 | private List roles; 42 | 43 | @CreatedDate 44 | private Instant created; 45 | 46 | @Indexed 47 | private Instant expiration; 48 | 49 | @Builder.Default 50 | private Map keyValueMap = new HashMap<>(); 51 | 52 | @Override 53 | public Map getKeyValues() { 54 | return keyValueMap; 55 | } 56 | 57 | @Override 58 | public void setKeyValues(Map map) { 59 | this.keyValueMap = map; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /commons-auth-mongo/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | io.rocketbase.commons.config.AuthMongoAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-mongo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.rocketbase.commons.config.AuthMongoAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-mongo/src/test/java/io/rocketbase/commons/Application.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | 10 | public static void main(String[] args) throws Exception { 11 | SpringApplication.run(Application.class, args); 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /commons-auth-mongo/src/test/java/io/rocketbase/commons/service/BaseIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service; 2 | 3 | import io.rocketbase.commons.Application; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.DynamicPropertyRegistry; 8 | import org.springframework.test.context.DynamicPropertySource; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | import org.testcontainers.containers.MongoDBContainer; 11 | import org.testcontainers.junit.jupiter.Container; 12 | import org.testcontainers.junit.jupiter.Testcontainers; 13 | import org.testcontainers.utility.DockerImageName; 14 | 15 | 16 | @Slf4j 17 | @RunWith(SpringRunner.class) 18 | @SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) 19 | @Testcontainers 20 | public abstract class BaseIntegrationTest { 21 | @Container 22 | protected static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4")); 23 | 24 | @DynamicPropertySource 25 | static void initTestContainerProperties(DynamicPropertyRegistry registry) { 26 | mongoDBContainer.start(); 27 | log.info("Setting spring.data.mongodb.uri = {}", mongoDBContainer.getReplicaSetUrl()); 28 | registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /commons-auth-mongo/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | main: 3 | allow-circular-references: true -------------------------------------------------------------------------------- /commons-auth-server/src/main/java/io/rocketbase/commons/controller/ImpersonateController.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | import io.rocketbase.commons.exception.NotFoundException; 5 | import io.rocketbase.commons.model.AppUserEntity; 6 | import io.rocketbase.commons.security.CommonsPrincipal; 7 | import io.rocketbase.commons.service.impersonate.ImpersonateService; 8 | import io.rocketbase.commons.service.user.ActiveUserStore; 9 | import io.rocketbase.commons.service.user.AppUserService; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 12 | import org.springframework.http.ResponseEntity; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import javax.annotation.Resource; 16 | 17 | @Slf4j 18 | @RestController 19 | @ConditionalOnExpression(value = "${auth.impersonate.enabled:true}") 20 | @RequestMapping("${auth.prefix:}") 21 | public class ImpersonateController implements BaseController { 22 | 23 | @Resource 24 | private AppUserService appUserService; 25 | 26 | @Resource 27 | private ImpersonateService impersonateService; 28 | 29 | @Resource 30 | private ActiveUserStore activeUserStore; 31 | 32 | @RequestMapping(method = RequestMethod.GET, path = "/api/impersonate/{userIdOrUsername}") 33 | @ResponseBody 34 | public ResponseEntity impersonate(@PathVariable("userIdOrUsername") String userIdOrUsername) { 35 | AppUserEntity impersonateUser = appUserService.findByIdOrUsername(userIdOrUsername).orElseThrow(NotFoundException::new); 36 | activeUserStore.addUser(impersonateUser); 37 | 38 | return ResponseEntity.ok(impersonateService.getImpersonateBundle(CommonsPrincipal.getCurrent(), impersonateUser)); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/EmailValidationExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller.exceptionhandler; 2 | 3 | import io.rocketbase.commons.dto.ErrorResponse; 4 | import io.rocketbase.commons.dto.validation.EmailErrorCodes; 5 | import io.rocketbase.commons.exception.EmailValidationException; 6 | import io.rocketbase.commons.exception.ErrorCodes; 7 | import io.rocketbase.commons.exception.ValidationErrorCode; 8 | import io.rocketbase.commons.util.Nulls; 9 | import org.springframework.web.bind.annotation.ControllerAdvice; 10 | import org.springframework.web.bind.annotation.ExceptionHandler; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | import org.springframework.web.bind.annotation.ResponseStatus; 13 | 14 | import javax.servlet.http.HttpServletRequest; 15 | 16 | import static org.springframework.http.HttpStatus.BAD_REQUEST; 17 | 18 | @ControllerAdvice 19 | public class EmailValidationExceptionHandler extends BaseExceptionHandler { 20 | 21 | @ExceptionHandler 22 | @ResponseStatus(BAD_REQUEST) 23 | @ResponseBody 24 | public ErrorResponse handleEmailValidationException(HttpServletRequest request, EmailValidationException e) { 25 | ErrorResponse response = new ErrorResponse(ErrorCodes.FORM_ERROR.getStatus(), translate(request, "auth.error.emailValidation", "Email is used or incorrect")); 26 | if (e.getErrors() != null) { 27 | for (ValidationErrorCode c : e.getErrors()) { 28 | response.addField(c.getField(), Nulls.notNull(c.getMessage(), c.getCode().getValue())); 29 | } 30 | } 31 | return response; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/PasswordValidationExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller.exceptionhandler; 2 | 3 | import io.rocketbase.commons.dto.ErrorResponse; 4 | import io.rocketbase.commons.dto.validation.PasswordErrorCodes; 5 | import io.rocketbase.commons.exception.ErrorCodes; 6 | import io.rocketbase.commons.exception.PasswordValidationException; 7 | import io.rocketbase.commons.exception.ValidationErrorCode; 8 | import io.rocketbase.commons.util.Nulls; 9 | import org.springframework.web.bind.annotation.ControllerAdvice; 10 | import org.springframework.web.bind.annotation.ExceptionHandler; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | import org.springframework.web.bind.annotation.ResponseStatus; 13 | 14 | import javax.servlet.http.HttpServletRequest; 15 | 16 | import static org.springframework.http.HttpStatus.BAD_REQUEST; 17 | 18 | @ControllerAdvice 19 | public class PasswordValidationExceptionHandler extends BaseExceptionHandler { 20 | 21 | @ExceptionHandler 22 | @ResponseStatus(BAD_REQUEST) 23 | @ResponseBody 24 | public ErrorResponse handlePasswordValidationException(HttpServletRequest request, PasswordValidationException e) { 25 | ErrorResponse response = new ErrorResponse(ErrorCodes.FORM_ERROR.getStatus(), translate(request, "auth.error.passwordValidation", "Password not fitting requirements")); 26 | if (e.getErrors() != null) { 27 | for (ValidationErrorCode c : e.getErrors()) { 28 | response.addField(c.getField(), Nulls.notNull(c.getMessage(), c.getCode().getValue())); 29 | } 30 | } 31 | return response; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/RegistrationExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller.exceptionhandler; 2 | 3 | import io.rocketbase.commons.dto.ErrorResponse; 4 | import io.rocketbase.commons.exception.AuthErrorCodes; 5 | import io.rocketbase.commons.exception.RegistrationException; 6 | import io.rocketbase.commons.exception.ValidationErrorCode; 7 | import io.rocketbase.commons.util.Nulls; 8 | import org.springframework.web.bind.annotation.ControllerAdvice; 9 | import org.springframework.web.bind.annotation.ExceptionHandler; 10 | import org.springframework.web.bind.annotation.ResponseBody; 11 | import org.springframework.web.bind.annotation.ResponseStatus; 12 | 13 | import javax.servlet.http.HttpServletRequest; 14 | import java.util.Set; 15 | 16 | import static org.springframework.http.HttpStatus.BAD_REQUEST; 17 | 18 | @ControllerAdvice 19 | public class RegistrationExceptionHandler extends BaseExceptionHandler { 20 | 21 | @ExceptionHandler 22 | @ResponseStatus(BAD_REQUEST) 23 | @ResponseBody 24 | public ErrorResponse handleRegistrationException(HttpServletRequest request, RegistrationException e) { 25 | ErrorResponse response = new ErrorResponse(AuthErrorCodes.REGISTRATION.getStatus(), translate(request, "auth.error.registration", "Registation failed")); 26 | addErrors(e.getUsernameErrors(), "username", response); 27 | addErrors(e.getPasswordErrors(), "password", response); 28 | addErrors(e.getEmailErrors(), "email", response); 29 | return response; 30 | } 31 | 32 | public > void addErrors(Set> errors, String path, ErrorResponse response) { 33 | if (errors != null && !errors.isEmpty()) { 34 | for (ValidationErrorCode v : errors) { 35 | response.addField(path, Nulls.notNull(v.getMessage(), v.getCode().name())); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/UnknownUserExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller.exceptionhandler; 2 | 3 | import io.rocketbase.commons.dto.ErrorResponse; 4 | import io.rocketbase.commons.exception.AuthErrorCodes; 5 | import io.rocketbase.commons.exception.UnknownUserException; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | import org.springframework.web.bind.annotation.ResponseStatus; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | 13 | import static org.springframework.http.HttpStatus.BAD_REQUEST; 14 | 15 | @ControllerAdvice 16 | public class UnknownUserExceptionHandler extends BaseExceptionHandler { 17 | 18 | @ExceptionHandler 19 | @ResponseStatus(BAD_REQUEST) 20 | @ResponseBody 21 | public ErrorResponse handleUnknownUserException(HttpServletRequest request, UnknownUserException e) { 22 | ErrorResponse errorResponse = new ErrorResponse(AuthErrorCodes.UNKNOWN_USER.getStatus(), translate(request, "auth.error.unknownUser", "User is unknown")); 23 | if (e.isEmail()) { 24 | errorResponse.addField("email", translate(request, "auth.error.unknownEmail", "Email is unknown")); 25 | } 26 | if (e.isUsername()) { 27 | errorResponse.addField("username", translate(request, "auth.error.unknownUser", "User is unknown")); 28 | } 29 | return errorResponse; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/UsernameValidationExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller.exceptionhandler; 2 | 3 | import io.rocketbase.commons.dto.ErrorResponse; 4 | import io.rocketbase.commons.dto.validation.UsernameErrorCodes; 5 | import io.rocketbase.commons.exception.ErrorCodes; 6 | import io.rocketbase.commons.exception.UsernameValidationException; 7 | import io.rocketbase.commons.exception.ValidationErrorCode; 8 | import io.rocketbase.commons.util.Nulls; 9 | import org.springframework.web.bind.annotation.ControllerAdvice; 10 | import org.springframework.web.bind.annotation.ExceptionHandler; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | import org.springframework.web.bind.annotation.ResponseStatus; 13 | 14 | import javax.servlet.http.HttpServletRequest; 15 | import java.util.HashMap; 16 | 17 | import static org.springframework.http.HttpStatus.BAD_REQUEST; 18 | 19 | @ControllerAdvice 20 | public class UsernameValidationExceptionHandler extends BaseExceptionHandler { 21 | 22 | @ExceptionHandler 23 | @ResponseStatus(BAD_REQUEST) 24 | @ResponseBody 25 | public ErrorResponse handleUsernameValidationException(HttpServletRequest request, UsernameValidationException e) { 26 | ErrorResponse response = new ErrorResponse(ErrorCodes.FORM_ERROR.getStatus(), translate(request, "auth.error.usernameValidation", "Username not fitting requirements")); 27 | response.setFields(new HashMap<>()); 28 | if (e.getErrors() != null) { 29 | for (ValidationErrorCode c : e.getErrors()) { 30 | response.addField(c.getField(), Nulls.notNull(c.getMessage(), c.getCode().getValue())); 31 | } 32 | } 33 | return response; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/VerificationExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller.exceptionhandler; 2 | 3 | import io.rocketbase.commons.dto.ErrorResponse; 4 | import io.rocketbase.commons.exception.AuthErrorCodes; 5 | import io.rocketbase.commons.exception.VerificationException; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | import org.springframework.web.bind.annotation.ResponseStatus; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | 13 | import static org.springframework.http.HttpStatus.BAD_REQUEST; 14 | 15 | @ControllerAdvice 16 | public class VerificationExceptionHandler extends BaseExceptionHandler { 17 | 18 | @ExceptionHandler 19 | @ResponseStatus(BAD_REQUEST) 20 | @ResponseBody 21 | public ErrorResponse handleVerificationException(HttpServletRequest request, VerificationException e) { 22 | return new ErrorResponse(AuthErrorCodes.VERIFICATION_INVALID.getStatus(), translate(request, "auth.error.verification", "Verification is invalid or expired")) 23 | .addField(e.getField(), translate(request, "auth.error.verification", "Verification is invalid or expired")); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /commons-auth-server/src/main/resources/META-INF/resources/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocketbase-io/commons-auth/c86f5c1caba8c63f9f91fd4828395162f35f23bc/commons-auth-server/src/main/resources/META-INF/resources/favicon.ico -------------------------------------------------------------------------------- /commons-auth-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | io.rocketbase.commons.config.AuthServerAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.rocketbase.commons.config.AuthServerAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-server/src/test/java/io/rocketbase/commons/BaseIntegrationTestPrefixed.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons; 2 | 3 | import io.rocketbase.commons.test.BaseIntegrationTest; 4 | 5 | public class BaseIntegrationTestPrefixed extends BaseIntegrationTest { 6 | 7 | @Override 8 | public String getBaseUrl() { 9 | // added prefix for testing... see: application-test.yml -> auth.prefix 10 | return super.getBaseUrl() + "/test"; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /commons-auth-server/src/test/java/io/rocketbase/commons/TestApplication.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons; 2 | 3 | import io.rocketbase.commons.service.email.EmailSender; 4 | import io.rocketbase.commons.test.EmailSenderTest; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | @SpringBootApplication 10 | public class TestApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(TestApplication.class, args); 14 | } 15 | 16 | @Bean 17 | public EmailSender emailSender() { 18 | return new EmailSenderTest(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /commons-auth-server/src/test/java/io/rocketbase/commons/controller/ImpersonateControllerTest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.controller; 2 | 3 | import io.rocketbase.commons.BaseIntegrationTestPrefixed; 4 | import io.rocketbase.commons.adapters.JwtRestTemplate; 5 | import io.rocketbase.commons.adapters.JwtTokenProvider; 6 | import io.rocketbase.commons.adapters.SimpleJwtTokenProvider; 7 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 8 | import io.rocketbase.commons.model.AppUserEntity; 9 | import io.rocketbase.commons.resource.ImpersonateResource; 10 | import io.rocketbase.commons.test.ModifiedJwtTokenService; 11 | import io.rocketbase.commons.util.JwtTokenBody; 12 | import io.rocketbase.commons.util.JwtTokenDecoder; 13 | import org.junit.Test; 14 | 15 | import javax.annotation.Resource; 16 | 17 | import static org.hamcrest.MatcherAssert.assertThat; 18 | import static org.hamcrest.Matchers.*; 19 | 20 | public class ImpersonateControllerTest extends BaseIntegrationTestPrefixed { 21 | 22 | @Resource 23 | private ModifiedJwtTokenService modifiedJwtTokenService; 24 | 25 | @Test 26 | public void impersonate() { 27 | // given 28 | AppUserEntity admin = getAppUser("admin"); 29 | JwtTokenProvider tokenProvider = new SimpleJwtTokenProvider(getBaseUrl(), modifiedJwtTokenService.generateTokenBundle(admin)); 30 | AppUserEntity user = getAppUser("user"); 31 | 32 | 33 | // when 34 | ImpersonateResource impersonateResource = new ImpersonateResource(new JwtRestTemplate(tokenProvider)); 35 | JwtTokenBundle response = impersonateResource.impersonate(user.getId()); 36 | 37 | // then 38 | assertThat(response, notNullValue()); 39 | JwtTokenBody jwtTokenBody = JwtTokenDecoder.decodeTokenBody(response.getToken()); 40 | assertThat(jwtTokenBody.getUsername(), equalTo(user.getUsername())); 41 | assertThat(jwtTokenBody.getScopes(), containsInAnyOrder("ROLE_" + user.getRoles().get(0))); 42 | } 43 | } -------------------------------------------------------------------------------- /commons-auth-server/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | # json configuration 3 | jackson: 4 | serialization: 5 | WRITE_DATES_AS_TIMESTAMPS: false 6 | INDENT_OUTPUT: true 7 | default-property-inclusion: NON_NULL 8 | # email 9 | mail: 10 | host: localhost 11 | username: username 12 | password: secret 13 | port: 2525 14 | properties: 15 | mail: 16 | debug: false 17 | smtp: 18 | debug: false 19 | auth: true 20 | starttls: true 21 | test-connection: false 22 | 23 | main: 24 | allow-circular-references: true 25 | 26 | logging: 27 | level: 28 | io.rocketbase: TRACE 29 | 30 | # auth configuration 31 | auth: 32 | jwt: 33 | secret: 'P0UoSCtNYlBlU2hWbVlxM3Q2dzl6JEMmRilKQE5jUmZUalduWnI0dTd4IUElRCpHLUthUGRTZ1ZrWHAyczV2OA==' 34 | user-cache-time: 0 35 | prefix: /test -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/api/AppInviteApiService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.converter.AppInviteConverter; 4 | import io.rocketbase.commons.dto.PageableResult; 5 | import io.rocketbase.commons.dto.appinvite.AppInviteRead; 6 | import io.rocketbase.commons.dto.appinvite.InviteRequest; 7 | import io.rocketbase.commons.dto.appinvite.QueryAppInvite; 8 | import io.rocketbase.commons.model.AppInviteEntity; 9 | import io.rocketbase.commons.service.invite.AppInviteService; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.data.domain.Page; 12 | import org.springframework.data.domain.Pageable; 13 | 14 | @RequiredArgsConstructor 15 | public class AppInviteApiService implements AppInviteApi, BaseApiService { 16 | 17 | private final AppInviteService appInviteService; 18 | private final AppInviteConverter converter; 19 | 20 | @Override 21 | public PageableResult find(QueryAppInvite query, Pageable pageable) { 22 | Page page = appInviteService.findAll(query, pageable); 23 | return PageableResult.contentPage(converter.fromEntities(page.getContent()), page); 24 | } 25 | 26 | @Override 27 | public AppInviteRead invite(InviteRequest inviteRequest) { 28 | return converter.fromEntity(appInviteService.createInvite(inviteRequest, getBaseUrl())); 29 | } 30 | 31 | @Override 32 | public void delete(String id) { 33 | appInviteService.deleteInvite(id); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/api/BaseApiService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.util.Nulls; 4 | import org.springframework.web.context.request.RequestContextHolder; 5 | import org.springframework.web.context.request.ServletRequestAttributes; 6 | import org.springframework.web.servlet.support.ServletUriComponentsBuilder; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | 10 | public interface BaseApiService { 11 | 12 | default String getBaseUrl() { 13 | try { 14 | ServletUriComponentsBuilder uriComponentsBuilder = ServletUriComponentsBuilder.fromCurrentContextPath(); 15 | // in some cases uriComponentsBuilder will ignore ssl (checks for X-Forwarded-Ssl: on) ignore this behaviour... 16 | HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 17 | String scheme = Nulls.notNull(request.getHeader("x-forwarded-proto"), request.getHeader("x-scheme")); 18 | if ("https".equalsIgnoreCase(scheme)) { 19 | uriComponentsBuilder.scheme(scheme); 20 | } 21 | return uriComponentsBuilder.toUriString(); 22 | } catch (Exception e) { 23 | } 24 | return null; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/api/ForgotPasswordApiService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.ExpirationInfo; 4 | import io.rocketbase.commons.dto.forgot.ForgotPasswordRequest; 5 | import io.rocketbase.commons.dto.forgot.PerformPasswordResetRequest; 6 | import io.rocketbase.commons.service.forgot.AppUserForgotPasswordService; 7 | import lombok.RequiredArgsConstructor; 8 | 9 | @RequiredArgsConstructor 10 | public class ForgotPasswordApiService implements ForgotPasswordApi, BaseApiService { 11 | 12 | private final AppUserForgotPasswordService forgotPasswordService; 13 | 14 | @Override 15 | public ExpirationInfo forgotPassword(ForgotPasswordRequest forgotPassword) { 16 | return forgotPasswordService.requestPasswordReset(forgotPassword, getBaseUrl()); 17 | } 18 | 19 | @Override 20 | public void resetPassword(PerformPasswordResetRequest performPasswordReset) { 21 | forgotPasswordService.resetPassword(performPasswordReset); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/api/ImpersonateApiService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | import io.rocketbase.commons.exception.NotFoundException; 5 | import io.rocketbase.commons.model.AppUserEntity; 6 | import io.rocketbase.commons.security.CommonsPrincipal; 7 | import io.rocketbase.commons.service.impersonate.ImpersonateService; 8 | import io.rocketbase.commons.service.user.AppUserService; 9 | import lombok.RequiredArgsConstructor; 10 | 11 | @RequiredArgsConstructor 12 | public class ImpersonateApiService implements ImpersonateApi { 13 | 14 | private final ImpersonateService impersonateService; 15 | private final AppUserService appUserService; 16 | 17 | @Override 18 | public JwtTokenBundle impersonate(String userIdOrUsername) { 19 | AppUserEntity entity = appUserService.findByIdOrUsername(userIdOrUsername).orElseThrow(NotFoundException::new); 20 | return impersonateService.getImpersonateBundle(CommonsPrincipal.getCurrent(), entity); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/api/InviteApiService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.converter.AppInviteConverter; 4 | import io.rocketbase.commons.converter.AppUserConverter; 5 | import io.rocketbase.commons.dto.appinvite.AppInviteRead; 6 | import io.rocketbase.commons.dto.appinvite.ConfirmInviteRequest; 7 | import io.rocketbase.commons.dto.appuser.AppUserRead; 8 | import io.rocketbase.commons.model.AppUserEntity; 9 | import io.rocketbase.commons.service.invite.AppInviteService; 10 | import lombok.RequiredArgsConstructor; 11 | 12 | @RequiredArgsConstructor 13 | public class InviteApiService implements InviteApi { 14 | 15 | private final AppInviteService appInviteService; 16 | private final AppInviteConverter inviteConverter; 17 | private final AppUserConverter userConverter; 18 | 19 | @Override 20 | public AppInviteRead verify(String inviteId) { 21 | return inviteConverter.fromEntity(appInviteService.verifyInvite(inviteId)); 22 | } 23 | 24 | @Override 25 | public AppUserRead transformToUser(ConfirmInviteRequest confirmInvite) { 26 | AppUserEntity userEntity = appInviteService.confirmInvite(confirmInvite); 27 | return userConverter.fromEntity(userEntity); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/api/LoginApiService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.authentication.LoginRequest; 4 | import io.rocketbase.commons.dto.authentication.LoginResponse; 5 | import io.rocketbase.commons.model.AppUserToken; 6 | import io.rocketbase.commons.security.JwtTokenService; 7 | import io.rocketbase.commons.service.auth.LoginService; 8 | import io.rocketbase.commons.service.user.AppUserService; 9 | import lombok.RequiredArgsConstructor; 10 | 11 | @RequiredArgsConstructor 12 | public class LoginApiService implements LoginApi { 13 | 14 | private final LoginService loginService; 15 | 16 | private final JwtTokenService jwtTokenService; 17 | 18 | private final AppUserService appUserService; 19 | 20 | @Override 21 | public LoginResponse login(LoginRequest login) { 22 | return loginService.performLogin(login.getUsername(), login.getPassword()); 23 | } 24 | 25 | @Override 26 | public String getNewAccessToken(String refreshToken) { 27 | AppUserToken appUserToken = jwtTokenService.parseToken(refreshToken); 28 | if (!appUserToken.hasRole(JwtTokenService.REFRESH_TOKEN)) { 29 | throw new RuntimeException("need a valid refresh-token!"); 30 | } 31 | return jwtTokenService.generateAccessToken(appUserService.getByUsername(appUserToken.getUsername())); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/api/RegistrationApiService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.converter.AppUserConverter; 4 | import io.rocketbase.commons.dto.ExpirationInfo; 5 | import io.rocketbase.commons.dto.appuser.AppUserRead; 6 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 7 | import io.rocketbase.commons.dto.registration.RegistrationRequest; 8 | import io.rocketbase.commons.model.AppUserEntity; 9 | import io.rocketbase.commons.security.JwtTokenService; 10 | import io.rocketbase.commons.service.registration.RegistrationService; 11 | import lombok.RequiredArgsConstructor; 12 | 13 | @RequiredArgsConstructor 14 | public class RegistrationApiService implements RegistrationApi, BaseApiService { 15 | 16 | private final RegistrationService registrationService; 17 | private final AppUserConverter converter; 18 | private final JwtTokenService jwtTokenService; 19 | 20 | @Override 21 | public ExpirationInfo register(RegistrationRequest registration) { 22 | ExpirationInfo expirationInfo = registrationService.register(registration, getBaseUrl()); 23 | return ExpirationInfo.builder() 24 | .expires(expirationInfo.getExpires()) 25 | .detail(converter.fromEntity(expirationInfo.getDetail())) 26 | .build(); 27 | } 28 | 29 | @Override 30 | public JwtTokenBundle verify(String verification) { 31 | AppUserEntity appUserEntity = registrationService.verifyRegistration(verification); 32 | return jwtTokenService.generateTokenBundle(appUserEntity); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/api/UserSearchApiService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.dto.PageableResult; 4 | import io.rocketbase.commons.dto.appuser.QueryAppUser; 5 | import io.rocketbase.commons.model.AppUserEntity; 6 | import io.rocketbase.commons.model.AppUserReference; 7 | import io.rocketbase.commons.service.user.AppUserService; 8 | import lombok.RequiredArgsConstructor; 9 | import org.springframework.data.domain.Page; 10 | import org.springframework.data.domain.Pageable; 11 | 12 | import java.util.Optional; 13 | import java.util.stream.Collectors; 14 | 15 | @RequiredArgsConstructor 16 | public class UserSearchApiService implements UserSearchApi { 17 | 18 | private final AppUserService appUserService; 19 | 20 | @Override 21 | public PageableResult search(QueryAppUser query, Pageable pageable) { 22 | Page page = appUserService.findAll(query, pageable); 23 | return PageableResult.contentPage(page.stream().map(AppUserEntity::toReference).collect(Collectors.toList()), page); 24 | } 25 | 26 | @Override 27 | public Optional findByUsernameOrId(String usernameOrId) { 28 | Optional optional = appUserService.findByIdOrUsername(usernameOrId); 29 | return optional.isPresent() ? Optional.of(optional.get().toReference()) : Optional.empty(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/api/ValidationApiService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.api; 2 | 3 | import io.rocketbase.commons.converter.ValidationConverter; 4 | import io.rocketbase.commons.dto.validation.*; 5 | import io.rocketbase.commons.exception.ValidationErrorCode; 6 | import io.rocketbase.commons.service.validation.ValidationService; 7 | import lombok.RequiredArgsConstructor; 8 | 9 | import java.util.Set; 10 | 11 | @RequiredArgsConstructor 12 | public class ValidationApiService implements ValidationApi { 13 | 14 | private final ValidationService validationService; 15 | 16 | @Override 17 | public ValidationResponse validatePassword(String password) { 18 | Set> details = validationService.getPasswordValidationDetails(null, password); 19 | return ValidationConverter.convert(details); 20 | } 21 | 22 | @Override 23 | public ValidationResponse validateUsername(String username) { 24 | Set> details = validationService.getUsernameValidationDetails(null, username); 25 | return ValidationConverter.convert(details); 26 | } 27 | 28 | @Override 29 | public ValidationResponse validateEmail(String email) { 30 | Set> details = validationService.getEmailValidationDetails(null, email); 31 | return ValidationConverter.convert(details); 32 | } 33 | 34 | @Override 35 | public ValidationResponse validateToken(String token) { 36 | Set> details = validationService.getTokenValidationDetails(token); 37 | return ValidationConverter.convert(details); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/service/auth/LoginService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.auth; 2 | 3 | import io.rocketbase.commons.dto.authentication.LoginResponse; 4 | 5 | public interface LoginService { 6 | 7 | LoginResponse performLogin(String username, String password); 8 | } 9 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/service/change/ChangeAppUserWithConfirmService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.change; 2 | 3 | import io.rocketbase.commons.dto.ExpirationInfo; 4 | import io.rocketbase.commons.dto.authentication.EmailChangeRequest; 5 | import io.rocketbase.commons.exception.EmailValidationException; 6 | import io.rocketbase.commons.exception.VerificationException; 7 | import io.rocketbase.commons.model.AppUserEntity; 8 | import io.rocketbase.commons.service.FeedbackActionService; 9 | 10 | public interface ChangeAppUserWithConfirmService extends FeedbackActionService { 11 | 12 | ExpirationInfo handleEmailChangeRequest(String userId, EmailChangeRequest changeRequest, String baseUrl) throws EmailValidationException; 13 | 14 | AppUserEntity confirmEmailChange(String verification) throws VerificationException; 15 | } 16 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/service/email/MailContentConfig.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.email; 2 | 3 | import io.rocketbase.commons.model.AppInviteEntity; 4 | import io.rocketbase.commons.model.AppUserReference; 5 | import io.rocketbase.mail.model.HtmlTextEmail; 6 | 7 | public interface MailContentConfig { 8 | 9 | HtmlTextEmail register(AppUserReference user, String actionUrl); 10 | 11 | String registerSubject(AppUserReference user); 12 | 13 | HtmlTextEmail forgotPassword(AppUserReference user, String actionUrl); 14 | 15 | String forgotPasswordSubject(AppUserReference user); 16 | 17 | HtmlTextEmail invite(AppInviteEntity invite, String actionUrl); 18 | 19 | String inviteSubject(AppInviteEntity invite); 20 | 21 | HtmlTextEmail changeEmail(AppUserReference user, String newEmailAddress, String actionUrl); 22 | 23 | String changeEmailSubject(AppUserReference user); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/service/forgot/AppUserForgotPasswordService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.forgot; 2 | 3 | import io.rocketbase.commons.dto.ExpirationInfo; 4 | import io.rocketbase.commons.dto.forgot.ForgotPasswordRequest; 5 | import io.rocketbase.commons.dto.forgot.PerformPasswordResetRequest; 6 | import io.rocketbase.commons.model.AppUserEntity; 7 | import io.rocketbase.commons.service.FeedbackActionService; 8 | 9 | public interface AppUserForgotPasswordService extends FeedbackActionService { 10 | 11 | ExpirationInfo requestPasswordReset(ForgotPasswordRequest forgotPassword, String baseUrl); 12 | 13 | AppUserEntity resetPassword(PerformPasswordResetRequest performPasswordReset); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/service/impersonate/DefaultImpersonateService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.impersonate; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | import io.rocketbase.commons.event.ImpersonateEvent; 5 | import io.rocketbase.commons.model.AppUserToken; 6 | import io.rocketbase.commons.security.JwtTokenService; 7 | import org.springframework.context.ApplicationEventPublisher; 8 | 9 | import javax.annotation.Resource; 10 | 11 | public class DefaultImpersonateService implements ImpersonateService { 12 | 13 | @Resource 14 | private JwtTokenService jwtTokenService; 15 | 16 | @Resource 17 | private ApplicationEventPublisher applicationEventPublisher; 18 | 19 | @Override 20 | public JwtTokenBundle getImpersonateBundle(AppUserToken requestedBy, AppUserToken impersonateAs) { 21 | applicationEventPublisher.publishEvent(new ImpersonateEvent(this, requestedBy, impersonateAs)); 22 | 23 | return jwtTokenService.generateTokenBundle(impersonateAs); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/service/impersonate/ImpersonateService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.impersonate; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | import io.rocketbase.commons.model.AppUserToken; 5 | 6 | public interface ImpersonateService { 7 | 8 | JwtTokenBundle getImpersonateBundle(AppUserToken requestedBy, AppUserToken impersonateAs); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/service/invite/AppInviteService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.invite; 2 | 3 | import io.rocketbase.commons.dto.appinvite.ConfirmInviteRequest; 4 | import io.rocketbase.commons.dto.appinvite.InviteRequest; 5 | import io.rocketbase.commons.dto.appinvite.QueryAppInvite; 6 | import io.rocketbase.commons.exception.BadRequestException; 7 | import io.rocketbase.commons.exception.NotFoundException; 8 | import io.rocketbase.commons.exception.RegistrationException; 9 | import io.rocketbase.commons.exception.VerificationException; 10 | import io.rocketbase.commons.model.AppInviteEntity; 11 | import io.rocketbase.commons.model.AppUserEntity; 12 | import io.rocketbase.commons.service.FeedbackActionService; 13 | import org.springframework.data.domain.Page; 14 | import org.springframework.data.domain.Pageable; 15 | 16 | public interface AppInviteService extends FeedbackActionService { 17 | 18 | /** 19 | * creates an invite and sent him a invite email. during confirm process invitor will fill required fields like username, password to a new user.
20 | * time for verification could be configure AuthProperties.inviteExpiration 21 | * 22 | * @throws BadRequestException 23 | */ 24 | AppInviteEntity createInvite(InviteRequest request, String baseUrl) throws BadRequestException; 25 | 26 | AppInviteEntity verifyInvite(String inviteId) throws VerificationException, NotFoundException; 27 | 28 | /** 29 | * checks verification-token, set password and possible update firstName, lastName 30 | * 31 | * @throws RegistrationException 32 | * @throws VerificationException 33 | */ 34 | AppUserEntity confirmInvite(ConfirmInviteRequest request) throws RegistrationException, VerificationException; 35 | 36 | /** 37 | * delegates query to persistence service
38 | * so that for all main function {@link AppInviteService} is the main service - by dealing with invites 39 | */ 40 | Page findAll(QueryAppInvite query, Pageable pageable); 41 | 42 | void deleteInvite(String inviteId); 43 | } 44 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/service/registration/RegistrationService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.registration; 2 | 3 | import io.rocketbase.commons.dto.ExpirationInfo; 4 | import io.rocketbase.commons.dto.registration.RegistrationRequest; 5 | import io.rocketbase.commons.exception.RegistrationException; 6 | import io.rocketbase.commons.exception.VerificationException; 7 | import io.rocketbase.commons.model.AppUserEntity; 8 | import io.rocketbase.commons.service.FeedbackActionService; 9 | 10 | public interface RegistrationService extends FeedbackActionService { 11 | 12 | ExpirationInfo register(RegistrationRequest registration, String baseUrl) throws RegistrationException; 13 | 14 | AppUserEntity verifyRegistration(String verification) throws VerificationException; 15 | } 16 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/java/io/rocketbase/commons/util/JwtTokenStoreService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.util; 2 | 3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle; 4 | import io.rocketbase.commons.exception.TokenRefreshException; 5 | import io.rocketbase.commons.model.AppUserToken; 6 | import io.rocketbase.commons.security.JwtTokenService; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | @Slf4j 10 | public class JwtTokenStoreService extends AbstractJwtTokenStore { 11 | 12 | private final JwtTokenService jwtTokenService; 13 | 14 | public JwtTokenStoreService(JwtTokenBundle tokenBundle, JwtTokenService jwtTokenService) { 15 | super(tokenBundle); 16 | this.jwtTokenService = jwtTokenService; 17 | } 18 | 19 | @Override 20 | public void refreshToken() throws TokenRefreshException { 21 | try { 22 | AppUserToken token = jwtTokenService.parseToken(getTokenBundle().getRefreshToken()); 23 | tokenBundle.setToken(jwtTokenService.generateAccessToken(token)); 24 | 25 | lastToken = null; 26 | exp = null; 27 | 28 | if (log.isTraceEnabled()) { 29 | log.trace("refreshed token before processing http-request"); 30 | } 31 | } catch (Exception e) { 32 | if (log.isDebugEnabled()) { 33 | log.debug("couldn't refresh token. got error: {}", e.getMessage()); 34 | } 35 | throw new TokenRefreshException(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /commons-auth-service/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | io.rocketbase.commons.config.AuthServiceAutoConfiguration,\ 3 | io.rocketbase.commons.config.AuthApiAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-service/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.rocketbase.commons.config.AuthServiceAutoConfiguration 2 | io.rocketbase.commons.config.AuthApiAutoConfiguration -------------------------------------------------------------------------------- /commons-auth-service/src/test/java/io/rocketbase/commons/Application.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons; 2 | 3 | import io.rocketbase.commons.service.email.EmailSender; 4 | import io.rocketbase.commons.test.EmailSenderTest; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | @SpringBootApplication 10 | public class Application { 11 | 12 | @Bean 13 | public EmailSender emailSender() { 14 | return new EmailSenderTest(); 15 | } 16 | 17 | public static void main(String[] args) throws Exception { 18 | SpringApplication.run(Application.class, args); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /commons-auth-service/src/test/java/io/rocketbase/commons/service/email/EmailServiceTest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.service.email; 2 | 3 | import io.rocketbase.commons.config.EmailProperties; 4 | import io.rocketbase.commons.model.AppUserEntity; 5 | import io.rocketbase.commons.test.BaseIntegrationTest; 6 | import io.rocketbase.commons.test.EmailSenderTest; 7 | import org.junit.Test; 8 | import org.springframework.context.i18n.LocaleContextHolder; 9 | 10 | import javax.annotation.Resource; 11 | import java.util.Locale; 12 | 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.hamcrest.Matchers.*; 15 | 16 | public class EmailServiceTest extends BaseIntegrationTest { 17 | 18 | @Resource 19 | private AuthEmailService emailService; 20 | 21 | @Resource 22 | private EmailSenderTest emailSenderTest; 23 | 24 | @Test 25 | public void simpleSendRegistrationEmail() throws Exception { 26 | // given 27 | AppUserEntity user = getAppUser(); 28 | 29 | EmailProperties emailProperties = new EmailProperties(); 30 | 31 | // when 32 | emailService.sentRegistrationEmail(user, "http://localhost:8080/?verification=token"); 33 | 34 | // then 35 | 36 | assertThat(emailSenderTest.getSubject(), startsWith(emailProperties.getSubjectPrefix() + " ")); 37 | assertThat(emailSenderTest.getTo().getEmail(), containsString(user.getEmail())); 38 | assertThat(emailSenderTest.getHtml().length(), greaterThan(0)); 39 | } 40 | 41 | @Test 42 | public void germanRegistrationEmail() throws Exception { 43 | // given 44 | AppUserEntity user = getAppUser(); 45 | 46 | EmailProperties emailProperties = new EmailProperties(); 47 | LocaleContextHolder.setLocale(Locale.GERMAN); 48 | 49 | // when 50 | emailService.sentRegistrationEmail(user, "http://localhost:8080/?verification=token"); 51 | 52 | // then 53 | 54 | assertThat(emailSenderTest.getSubject(), is(String.format("%s Registrierung bestätigen", emailProperties.getSubjectPrefix()))); 55 | assertThat(emailSenderTest.getText(), containsString("Sie Ihre Registrierung durch einen Klick auf den")); 56 | } 57 | 58 | 59 | 60 | } -------------------------------------------------------------------------------- /commons-auth-service/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | # json configuration 3 | jackson: 4 | serialization: 5 | WRITE_DATES_AS_TIMESTAMPS: false 6 | INDENT_OUTPUT: true 7 | default-property-inclusion: NON_NULL 8 | # email 9 | mail: 10 | host: localhost 11 | username: username 12 | password: secret 13 | port: 2525 14 | properties: 15 | mail: 16 | debug: false 17 | smtp: 18 | debug: false 19 | auth: true 20 | starttls: true 21 | test-connection: false 22 | 23 | main: 24 | allow-circular-references: true 25 | 26 | logging: 27 | level: 28 | io.rocketbase: TRACE 29 | 30 | # auth configuration 31 | auth: 32 | jwt: 33 | secret: 'P0UoSCtNYlBlU2hWbVlxM3Q2dzl6JEMmRilKQE5jUmZUalduWnI0dTd4IUElRCpHLUthUGRTZ1ZrWHAyczV2OA==' 34 | user-cache-time: 0 35 | prefix: /test -------------------------------------------------------------------------------- /commons-auth-test/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | commons-auth 7 | io.rocketbase.commons 8 | LATEST-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | commons-auth-test 13 | 14 | 15 | 16 | io.rocketbase.commons 17 | commons-auth-core 18 | ${project.version} 19 | 20 | 21 | javax.annotation 22 | javax.annotation-api 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-test 27 | 28 | 29 | junit 30 | junit 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /commons-auth-test/src/main/java/io/rocketbase/commons/test/BaseIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.test; 2 | 3 | 4 | import io.rocketbase.commons.model.AppUserEntity; 5 | import io.rocketbase.commons.security.JwtTokenService; 6 | import io.rocketbase.commons.test.adapters.AuthRestTestTemplate; 7 | import lombok.Getter; 8 | import org.junit.Before; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.test.context.ActiveProfiles; 13 | import org.springframework.test.context.junit4.SpringRunner; 14 | 15 | import javax.annotation.Resource; 16 | 17 | @RunWith(SpringRunner.class) 18 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 19 | @ActiveProfiles(profiles = "test") 20 | public abstract class BaseIntegrationTest { 21 | 22 | @Getter 23 | @Value("http://localhost:${local.server.port}") 24 | protected String baseUrl; 25 | 26 | @Resource 27 | private AppUserPersistenceTestService appUserPersistenceTestService; 28 | 29 | @Resource 30 | private JwtTokenService jwtTokenService; 31 | 32 | protected AppUserEntity getAppUser() { 33 | return getAppUser("user"); 34 | } 35 | 36 | protected AppUserEntity getAppAdminUser() { 37 | return getAppUser("admin"); 38 | } 39 | 40 | protected AppUserEntity getAppUser(String username) { 41 | return appUserPersistenceTestService.findByUsername(username).get(); 42 | } 43 | 44 | protected AuthRestTestTemplate getAuthRestTemplate() { 45 | return getAuthRestTemplate("user"); 46 | } 47 | 48 | protected AuthRestTestTemplate getAuthRestAdminTemplate() { 49 | return getAuthRestTemplate("admin"); 50 | } 51 | 52 | protected AuthRestTestTemplate getAuthRestTemplate(String username) { 53 | return new AuthRestTestTemplate(getAppUser(username), jwtTokenService); 54 | } 55 | 56 | @Before 57 | public void beforeEachTest() { 58 | appUserPersistenceTestService.resetData(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /commons-auth-test/src/main/java/io/rocketbase/commons/test/EmailSenderTest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.test; 2 | 3 | import io.rocketbase.commons.service.email.EmailAddress; 4 | import io.rocketbase.commons.service.email.EmailSender; 5 | import lombok.Getter; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | @Slf4j 9 | @Getter 10 | public class EmailSenderTest implements EmailSender { 11 | 12 | private EmailAddress to; 13 | private String subject; 14 | private String html; 15 | private String text; 16 | private EmailAddress from; 17 | 18 | 19 | @Override 20 | public void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from) { 21 | this.to = to; 22 | this.subject = subject; 23 | this.html = html; 24 | this.text = text; 25 | this.from = from; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /commons-auth-test/src/main/java/io/rocketbase/commons/test/ModifiedJwtTokenService.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.test; 2 | 3 | import io.rocketbase.commons.config.JwtProperties; 4 | import io.rocketbase.commons.model.AppUserEntity; 5 | import io.rocketbase.commons.security.EmptyCustomAuthoritiesProvider; 6 | import io.rocketbase.commons.security.JwtTokenService; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.time.Instant; 12 | 13 | @Slf4j 14 | @Component 15 | public class ModifiedJwtTokenService extends JwtTokenService { 16 | 17 | @Autowired 18 | public ModifiedJwtTokenService(JwtProperties jwtProperties) { 19 | super(jwtProperties, new EmptyCustomAuthoritiesProvider()); 20 | } 21 | 22 | public String generateExpiredToken(AppUserEntity user) { 23 | return generateAccessToken(Instant.now().minusSeconds(60 * 60 * 24 * 100), user); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /commons-auth-test/src/main/java/io/rocketbase/commons/test/adapters/AuthRestTestTemplate.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.test.adapters; 2 | 3 | import io.rocketbase.commons.model.AppUserToken; 4 | import io.rocketbase.commons.resource.BasicResponseErrorHandler; 5 | import io.rocketbase.commons.security.JwtTokenService; 6 | import lombok.RequiredArgsConstructor; 7 | import org.apache.http.client.methods.HttpUriRequest; 8 | import org.springframework.http.HttpHeaders; 9 | import org.springframework.http.client.ClientHttpRequestFactory; 10 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; 11 | import org.springframework.web.client.RestTemplate; 12 | 13 | public class AuthRestTestTemplate extends RestTemplate { 14 | 15 | public AuthRestTestTemplate(AppUserToken userToken, JwtTokenService jwtTokenService) { 16 | super(new TestClientHttpRequestFactory(userToken, jwtTokenService)); 17 | setErrorHandler(new BasicResponseErrorHandler()); 18 | } 19 | 20 | @RequiredArgsConstructor 21 | protected static class TestClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory implements ClientHttpRequestFactory { 22 | private final AppUserToken userToken; 23 | private final JwtTokenService jwtTokenService; 24 | 25 | @Override 26 | protected void postProcessHttpRequest(HttpUriRequest request) { 27 | request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + jwtTokenService.generateAccessToken(userToken)); 28 | } 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /commons-auth-test/src/main/java/io/rocketbase/commons/test/model/AppInviteTestEntity.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.test.model; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import io.rocketbase.commons.model.AppInviteEntity; 5 | import lombok.*; 6 | 7 | import java.time.Instant; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.stream.Collectors; 12 | 13 | 14 | @Data 15 | @Builder 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @EqualsAndHashCode(of = {"id"}) 19 | public class AppInviteTestEntity implements AppInviteEntity { 20 | 21 | private String id; 22 | 23 | private String invitor; 24 | 25 | private String message; 26 | 27 | private String firstName; 28 | 29 | private String lastName; 30 | 31 | private String email; 32 | 33 | private List roles; 34 | 35 | @Builder.Default 36 | private Map keyValueMap = new HashMap<>(); 37 | 38 | 39 | private Instant created; 40 | 41 | private Instant expiration; 42 | 43 | @Override 44 | public AppInviteTestEntity clone() { 45 | Map copyedKeyValueMap = getKeyValueMap() != null ? new HashMap<>(ImmutableMap.copyOf(getKeyValueMap())) : null; 46 | return AppInviteTestEntity.builder() 47 | .id(getId()) 48 | .invitor(getInvitor()) 49 | .message(getMessage()) 50 | .email(getEmail()) 51 | .roles(getRoles() != null ? getRoles().stream().map(r -> String.valueOf(r)).collect(Collectors.toList()) : null) 52 | .firstName(getFirstName()) 53 | .lastName(getLastName()) 54 | .created(getCreated()) 55 | .expiration(getExpiration()) 56 | .keyValueMap(copyedKeyValueMap) 57 | .build(); 58 | } 59 | 60 | @Override 61 | public Map getKeyValues() { 62 | return keyValueMap; 63 | } 64 | 65 | @Override 66 | public void setKeyValues(Map map) { 67 | this.keyValueMap = map; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /commons-auth-test/src/test/java/io/rocketbase/commons/converter/AppUserConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.rocketbase.commons.converter; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import io.rocketbase.commons.dto.appuser.AppUserRead; 5 | import io.rocketbase.commons.model.AppUserEntity; 6 | import io.rocketbase.commons.test.model.AppUserTestEntity; 7 | import org.junit.Test; 8 | 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.equalTo; 11 | import static org.hamcrest.Matchers.notNullValue; 12 | 13 | public class AppUserConverterTest { 14 | 15 | @Test 16 | public void fromEntity() { 17 | // given 18 | AppUserEntity entity = AppUserTestEntity.builder() 19 | .id("id") 20 | .email("email@test.io") 21 | .keyValueMap(ImmutableMap.builder() 22 | .put("test", "value") 23 | .put("_secret", "1234") 24 | .build()) 25 | .build(); 26 | 27 | // when 28 | AppUserRead appUserRead = new AppUserConverter().fromEntity(entity); 29 | 30 | // then 31 | assertThat(appUserRead, notNullValue()); 32 | assertThat(appUserRead.getId(), equalTo("id")); 33 | assertThat(appUserRead.getEmail(), equalTo("email@test.io")); 34 | assertThat(appUserRead.getKeyValues().keySet().contains("test"), equalTo(true)); 35 | assertThat(appUserRead.getKeyValues().keySet().contains("_secret"), equalTo(false)); 36 | } 37 | } -------------------------------------------------------------------------------- /lombok.config: -------------------------------------------------------------------------------- 1 | lombok.addLombokGeneratedAnnotation = true --------------------------------------------------------------------------------