├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main └── java │ └── uk │ └── co │ └── caeldev │ └── springsecuritymongo │ ├── MongoApprovalStore.java │ ├── MongoClientDetailsService.java │ ├── MongoClientTokenServices.java │ ├── MongoTokenStore.java │ ├── MongoUserDetailsManager.java │ ├── config │ ├── EnableSecurityMongo.java │ ├── MongoConfiguration.java │ └── MongoSettings.java │ ├── domain │ ├── MongoApproval.java │ ├── MongoClientDetails.java │ ├── MongoOAuth2AccessToken.java │ ├── MongoOAuth2ClientToken.java │ ├── MongoOAuth2RefreshToken.java │ └── User.java │ ├── repositories │ ├── MongoApprovalRepository.java │ ├── MongoApprovalRepositoryBase.java │ ├── MongoApprovalRepositoryImpl.java │ ├── MongoClientDetailsRepository.java │ ├── MongoClientDetailsRepositoryBase.java │ ├── MongoClientDetailsRepositoryImpl.java │ ├── MongoOAuth2AccessTokenRepository.java │ ├── MongoOAuth2AccessTokenRepositoryBase.java │ ├── MongoOAuth2AccessTokenRepositoryImpl.java │ ├── MongoOAuth2ClientTokenRepository.java │ ├── MongoOAuth2ClientTokenRepositoryBase.java │ ├── MongoOAuth2ClientTokenRepositoryImpl.java │ ├── MongoOAuth2RefreshTokenRepository.java │ ├── MongoOAuth2RefreshTokenRepositoryBase.java │ ├── MongoOAuth2RefreshTokenRepositoryImpl.java │ ├── UserRepository.java │ ├── UserRepositoryBase.java │ └── UserRepositoryImpl.java │ ├── services │ └── SecurityContextService.java │ └── util │ └── LocalDateTimeUtil.java └── test ├── java └── uk │ └── co │ └── caeldev │ └── springsecuritymongo │ ├── MongoApprovalStoreTest.java │ ├── MongoClientDetailsServiceIntegrationTest.java │ ├── MongoClientDetailsServiceTest.java │ ├── MongoClientTokenServicesTest.java │ ├── MongoTokenStoreTest.java │ ├── MongoUserDetailsManagerTest.java │ ├── builders │ ├── ApprovalBuilder.java │ ├── ClientDetailsBuilder.java │ ├── MongoApprovalBuilder.java │ ├── MongoClientDetailsBuilder.java │ ├── MongoOAuth2AccessTokenBuilder.java │ ├── MongoOAuth2ClientTokenBuilder.java │ ├── MongoOAuth2RefreshTokenBuilder.java │ ├── OAuth2AccessTokenBuilder.java │ ├── OAuth2AuthenticationBuilder.java │ ├── OAuth2ProtectedResourceDetailsBuilder.java │ ├── OAuth2RefreshTokenBuilder.java │ ├── OAuth2RequestBuilder.java │ └── UserBuilder.java │ ├── commons │ └── SecurityRDG.java │ ├── config │ ├── ApplicationConfiguration.java │ └── MongoClientConfiguration.java │ ├── repositories │ ├── AbstractRepositoryIntegrationTest.java │ ├── MongoApprovalRepositoryIntegrationTest.java │ ├── MongoClientDetailsRepositoryIntegrationTest.java │ ├── MongoOAuth2AccessTokenRepositoryIntegrationTest.java │ ├── MongoOAuth2ClientTokenRepositoryIntegrationTest.java │ ├── MongoOAuth2RefreshTokenRepositoryIntegrationTest.java │ └── UserRepositoryIntegrationTest.java │ └── services │ └── SecurityContextServiceTest.java └── resources ├── application.yml ├── logback-test.xml └── samples └── mongoAccessTokens.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | *.iws 4 | *.ipr 5 | build/ 6 | .gradle 7 | out/ 8 | 9 | # Mac 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | notifications: 5 | email: 6 | recipients: 7 | - adolfoecs@gmail.com 8 | 9 | after_success: 10 | - ./gradlew jacocoTestReport coveralls -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Adolfo Ernesto Custidiano Secchi 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Security Mongo 2 | 3 | [![Build Status](https://travis-ci.org/caelcs/spring-security-mongo.svg?branch=master)](https://travis-ci.org/caelcs/spring-security-mongo) 4 | [![Coverage Status](https://coveralls.io/repos/github/caelcs/spring-security-mongo/badge.svg)](https://coveralls.io/github/caelcs/spring-security-mongo) 5 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/uk.co.caeldev/spring-security-mongo/badge.png?style=flat)](http://search.maven.org/#search|ga|1|g%3A%22uk.co.caeldev%22%20AND%20a%3A%22spring-security-mongo%22) 6 | 7 | Library to provide full implementation of all the repositories 8 | and provider necessary to have all the security persisted in MongoDB. 9 | 10 | * ApprovalStore 11 | * ClientDetailsService 12 | * ClientRegistrationService 13 | * TokenStore 14 | * UserDetailsManager 15 | * ClientTokenServices 16 | 17 | ### Important 18 | The library does not provides the necessary config to use these services, you will have to do that for your self. On the other hand I have another library that you can use shows how to configure all the services and have up and running your oauth2 server. 19 | 20 | https://github.com/caelcs/base-auth2-server 21 | 22 | ## How to use it 23 | 24 | ### Step 1 25 | Add as dependency to your project and then use the beans in your Spring Oauth2 Configuration 26 | 27 | #### Note: 28 | 29 | Spring Boot 2.x and Oath2 library and Mongo Driver 3.6 has bring a lot of changes that are not backward compatible unless that you play around with dependencies. 30 | So I have updated all the dependencies to use the latest from version 3.0.0. 31 | 32 | - Spring Boot 1.5.x -> use 2.0.0 33 | - Spring Boot 2.x.x -> use 3.0.0 34 | 35 | ### Step 2 36 | Add this annotation to your configuration class: 37 | 38 | ```java 39 | @Configuration 40 | @EnableSecurityMongo 41 | public class MongoSecurityConfiguration { 42 | 43 | } 44 | ``` 45 | Having this annotation will define in your spring context all the necessary to use this library. 46 | 47 | ### Step 3 48 | Create in your mongo instance the user that you will use to access the database 49 | 50 | ```json 51 | db.createUser( 52 | { 53 | user: "oauth2", 54 | pwd: "testpass", 55 | roles: [ { role: "readWrite", db: "invoicer" } ] 56 | } 57 | ) 58 | ``` 59 | 60 | ### Step 4 61 | define the following properties in your app if you want to use the default Mongo client. 62 | If you want to use your own version just DO NOT ADD these properties. 63 | 64 | ``` 65 | mongo.host=localhost 66 | mongo.port=27017 67 | mongo.database=testdb 68 | mongo.username=testuser 69 | mongo.password=testpassword 70 | ``` 71 | 72 | ## Creating users manually in Mongo DB 73 | 74 | You can produce the json to create in your mongo instance the users by executing some of the integration tests or just insert this json: 75 | 76 | Mongo User 77 | ```javascript 78 | { 79 | "_id" : "testuser", 80 | "_class" : "uk.co.caeldev.springsecuritymongo.domain.User", 81 | "password" : "testpassword", 82 | "userUUID" : LUUID("03479d48-93cf-5e55-974f-842eb0200ca8"), 83 | "authorities" : [ 84 | { 85 | "role" : "ROLE_USER", 86 | "_class" : "org.springframework.security.core.authority.SimpleGrantedAuthority" 87 | } 88 | ], 89 | "accountNonExpired" : true, 90 | "accountNonLocked" : true, 91 | "credentialsNonExpired" : true, 92 | "enabled" : true 93 | } 94 | ``` 95 | 96 | Mongo Client Detail 97 | 98 | ```javascript 99 | { 100 | "_id" : "testclient", 101 | "_class" : "uk.co.caeldev.springsecuritymongo.domain.MongoClientDetails", 102 | "clientSecret" : "testclientsecret", 103 | "scope" : [ 104 | "read" 105 | ], 106 | "resourceIds" : [ 107 | "oauth2-resource" 108 | ], 109 | "authorizedGrantTypes" : [ 110 | "authorization_code", 111 | "implicit" 112 | ], 113 | "registeredRedirectUris" : [ 114 | "http://www.google.co.uk" 115 | ], 116 | "authorities" : [ 117 | { 118 | "role" : "ROLE_CLIENT", 119 | "_class" : "org.springframework.security.core.authority.SimpleGrantedAuthority" 120 | } 121 | ], 122 | "accessTokenValiditySeconds" : 30000.0000000000000000, 123 | "refreshTokenValiditySeconds" : 30000.0000000000000000, 124 | "additionalInformation" : {}, 125 | "autoApproveScopes" : [ 126 | "" 127 | ] 128 | } 129 | ``` 130 | 131 | 132 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath("pl.allegro.tech.build:axion-release-plugin:${axionReleasePluginVersion}") 9 | classpath "org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.8.2" 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'idea' 15 | apply plugin: 'signing' 16 | apply plugin: 'maven' 17 | apply plugin: 'pl.allegro.tech.build.axion-release' 18 | apply plugin: 'jacoco' 19 | apply plugin: "com.github.kt3k.coveralls" 20 | 21 | sourceCompatibility = 1.8 22 | targetCompatibility = 1.8 23 | 24 | repositories { 25 | jcenter() 26 | mavenCentral() 27 | maven { 28 | url "https://oss.jfrog.org/libs-snapshot/" 29 | } 30 | } 31 | 32 | scmVersion { 33 | tag { 34 | prefix = 'RELEASE' 35 | } 36 | } 37 | 38 | group = 'uk.co.caeldev' 39 | version = scmVersion.version 40 | 41 | task javadocJar(type: Jar, dependsOn: javadoc) { 42 | classifier = 'javadoc' 43 | from 'build/docs/javadoc' 44 | } 45 | 46 | task sourcesJar(type: Jar) { 47 | from sourceSets.main.allSource 48 | classifier = 'sources' 49 | } 50 | 51 | jar { 52 | archivesBaseName = rootProject.name 53 | group = group 54 | version = version 55 | manifest { 56 | attributes 'Implementation-Title': 'Spring Security Mongo', 57 | 'Implementation-Version': version, 58 | 'Built-By': System.getProperty('user.name'), 59 | 'Built-Date': new Date(), 60 | 'Built-JDK': System.getProperty('java.version'), 61 | 'Built-Gradle': gradle.gradleVersion 62 | } 63 | } 64 | 65 | artifacts { 66 | archives jar 67 | archives javadocJar 68 | archives sourcesJar 69 | } 70 | 71 | signing { 72 | sign configurations.archives 73 | required = { gradle.taskGraph.hasTask("uploadArchives") && !version.endsWith("SNAPSHOT") } 74 | } 75 | 76 | jacocoTestReport { 77 | reports { 78 | xml.enabled true 79 | csv.enabled false 80 | html.enabled false 81 | html.destination file("${buildDir}/jacoco") 82 | } 83 | } 84 | 85 | uploadArchives { 86 | repositories { 87 | mavenDeployer { 88 | beforeDeployment { deployment -> signing.signPom(deployment) } 89 | 90 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2") { 91 | authentication(userName: "${System.env.ossrhUsername}", password: "${System.env.ossrhPassword}") 92 | } 93 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots") { 94 | authentication(userName: "${System.env.ossrhUsername}", password: "${System.env.ossrhPassword}") 95 | } 96 | 97 | //repository(url: "/Users/me/.m2/repository") 98 | 99 | pom.project { 100 | 101 | parent { 102 | groupId 'org.springframework.boot' 103 | artifactId 'spring-boot-starter-parent' 104 | version "${springBootVersion}" 105 | } 106 | 107 | name 'Spring Security Mongo' 108 | packaging "jar" 109 | 110 | description "A Commons Library to provide the repositories for mongo db" 111 | url "https://github.com/caelcs/spring-security-mongo" 112 | 113 | scm { 114 | url "https://github.com/caelcs/spring-security-mongo.git" 115 | connection "https://github.com/caelcs/spring-security-mongo.git" 116 | developerConnection "https://github.com/caelcs/spring-security-mongo.git" 117 | } 118 | 119 | licenses { 120 | license { 121 | name "MIT" 122 | url "http://opensource.org/licenses/MIT" 123 | distribution "repo" 124 | } 125 | } 126 | 127 | developers { 128 | developer { 129 | id "caelcs" 130 | name "Adolfo Custidiano" 131 | email "adolfoecs@gmail.com" 132 | } 133 | } 134 | } 135 | } 136 | } 137 | } 138 | 139 | coveralls { 140 | jacocoReportPath 'build/reports/jacoco/test/jacocoTestReport.xml' 141 | } 142 | 143 | tasks.coveralls { 144 | dependsOn 'check' 145 | } 146 | 147 | 148 | dependencies { 149 | implementation "org.springframework.boot:spring-boot-starter-web:${springBootVersion}" 150 | implementation "org.springframework.boot:spring-boot-starter-security:${springBootVersion}" 151 | implementation "org.springframework.boot:spring-boot-starter-data-mongodb:${springBootVersion}" 152 | implementation "org.springframework.security.oauth:spring-security-oauth2:${springOAuth2Version}" 153 | implementation "com.google.guava:guava:${guavaVersion}" 154 | implementation "com.fasterxml.jackson.core:jackson-databind" 155 | implementation "org.apache.commons:commons-lang3:3.7" 156 | 157 | 158 | testImplementation "org.springframework.boot:spring-boot-starter-test:${springBootVersion}" 159 | testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" 160 | testImplementation "uk.org.fyodor:fyodor-core:${fyodorVersion}" 161 | testImplementation "com.github.fakemongo:fongo:${fongoVersion}" 162 | testImplementation "com.lordofthejars:nosqlunit-mongodb:${nosqlunitMongodbVersion}" 163 | testImplementation "com.jayway.jsonpath:json-path:${jsonPathVersion}" 164 | } 165 | 166 | task wrapper(type: Wrapper) { 167 | gradleVersion = rootGradleVersion 168 | } 169 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | springBootVersion=2.0.1.RELEASE 2 | axionReleasePluginVersion=1.9.0 3 | rootGradleVersion=4.6 4 | 5 | guavaVersion=19.0 6 | apacheCommonsLang3Version=3.7 7 | jodaTimeVersion=2.5 8 | springOAuth2Version=2.3.0.RELEASE 9 | 10 | assertjCoreVersion=3.5.2 11 | fyodorVersion=1.0.0 12 | fongoVersion=2.2.0-RC1 13 | nosqlunitMongodbVersion=0.14.0 14 | jsonPathVersion=0.9.1 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caelcs/spring-security-mongo/540e8a2d76b9847ce9617c485b8f9cee9de9ba4b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Apr 10 10:02:16 BST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'spring-security-mongo' 2 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/MongoApprovalStore.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import org.springframework.security.oauth2.provider.approval.Approval; 4 | import org.springframework.security.oauth2.provider.approval.ApprovalStore; 5 | import org.springframework.stereotype.Component; 6 | import uk.co.caeldev.springsecuritymongo.domain.MongoApproval; 7 | import uk.co.caeldev.springsecuritymongo.repositories.MongoApprovalRepository; 8 | 9 | import java.time.LocalDateTime; 10 | import java.time.ZoneId; 11 | import java.util.Collection; 12 | import java.util.Date; 13 | import java.util.List; 14 | import java.util.UUID; 15 | import java.util.stream.Collectors; 16 | 17 | import static java.util.Objects.isNull; 18 | import static uk.co.caeldev.springsecuritymongo.util.LocalDateTimeUtil.convertTolocalDateTimeFrom; 19 | 20 | @Component 21 | public class MongoApprovalStore implements ApprovalStore { 22 | 23 | private final MongoApprovalRepository mongoApprovalRepository; 24 | 25 | private boolean handleRevocationsAsExpiry = false; 26 | 27 | public MongoApprovalStore(final MongoApprovalRepository mongoApprovalRepository) { 28 | this.mongoApprovalRepository = mongoApprovalRepository; 29 | } 30 | 31 | @Override 32 | public boolean addApprovals(final Collection approvals) { 33 | final Collection mongoApprovals = transformToMongoApproval(approvals); 34 | 35 | return mongoApprovalRepository.updateOrCreate(mongoApprovals); 36 | } 37 | 38 | @Override 39 | public boolean revokeApprovals(final Collection approvals) { 40 | boolean success = true; 41 | 42 | final Collection mongoApprovals = transformToMongoApproval(approvals); 43 | 44 | for (final MongoApproval mongoApproval : mongoApprovals) { 45 | if (handleRevocationsAsExpiry) { 46 | final boolean updateResult = mongoApprovalRepository.updateExpiresAt(LocalDateTime.now(), mongoApproval); 47 | if (!updateResult) { 48 | success = false; 49 | } 50 | 51 | } 52 | else { 53 | final boolean deleteResult = mongoApprovalRepository.deleteByUserIdAndClientIdAndScope(mongoApproval); 54 | 55 | if (!deleteResult) { 56 | success = false; 57 | } 58 | } 59 | } 60 | return success; 61 | } 62 | 63 | @Override 64 | public Collection getApprovals(final String userId, 65 | final String clientId) { 66 | final List mongoApprovals = mongoApprovalRepository.findByUserIdAndClientId(userId, clientId); 67 | return transformToApprovals(mongoApprovals); 68 | } 69 | 70 | private List transformToApprovals(final List mongoApprovals) { 71 | return mongoApprovals.stream().map(mongoApproval -> new Approval(mongoApproval.getUserId(), 72 | mongoApproval.getClientId(), 73 | mongoApproval.getScope(), 74 | Date.from(mongoApproval.getExpiresAt().atZone(ZoneId.systemDefault()).toInstant()), 75 | mongoApproval.getStatus(), 76 | Date.from(mongoApproval.getLastUpdatedAt().atZone(ZoneId.systemDefault()).toInstant()))) 77 | .collect(Collectors.toList()); 78 | } 79 | 80 | private List transformToMongoApproval(final Collection approvals) { 81 | return approvals.stream().map(approval -> new MongoApproval(UUID.randomUUID().toString(), 82 | approval.getUserId(), 83 | approval.getClientId(), 84 | approval.getScope(), 85 | isNull(approval.getStatus()) ? Approval.ApprovalStatus.APPROVED: approval.getStatus(), 86 | convertTolocalDateTimeFrom(approval.getExpiresAt()), 87 | convertTolocalDateTimeFrom(approval.getLastUpdatedAt()))).collect(Collectors.toList()); 88 | } 89 | 90 | public void setHandleRevocationsAsExpiry(boolean handleRevocationsAsExpiry) { 91 | this.handleRevocationsAsExpiry = handleRevocationsAsExpiry; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/MongoClientDetailsService.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import org.springframework.security.crypto.password.PasswordEncoder; 4 | import org.springframework.security.oauth2.provider.*; 5 | import org.springframework.stereotype.Component; 6 | import uk.co.caeldev.springsecuritymongo.domain.MongoClientDetails; 7 | import uk.co.caeldev.springsecuritymongo.repositories.MongoClientDetailsRepository; 8 | 9 | import java.util.List; 10 | import java.util.Set; 11 | import java.util.stream.Collectors; 12 | 13 | import static com.google.common.collect.Lists.newArrayList; 14 | import static com.google.common.collect.Sets.newHashSet; 15 | 16 | @Component 17 | public class MongoClientDetailsService implements ClientDetailsService, ClientRegistrationService { 18 | 19 | private final MongoClientDetailsRepository mongoClientDetailsRepository; 20 | 21 | private final PasswordEncoder passwordEncoder; 22 | 23 | public MongoClientDetailsService(final MongoClientDetailsRepository mongoClientDetailsRepository, 24 | final PasswordEncoder passwordEncoder) { 25 | this.mongoClientDetailsRepository = mongoClientDetailsRepository; 26 | this.passwordEncoder = passwordEncoder; 27 | } 28 | 29 | @Override 30 | public ClientDetails loadClientByClientId(final String clientId) { 31 | try { 32 | return mongoClientDetailsRepository.findByClientId(clientId); 33 | } catch (IllegalArgumentException e) { 34 | throw new ClientRegistrationException("No Client Details for client id", e); 35 | } 36 | } 37 | 38 | @Override 39 | public void addClientDetails(final ClientDetails clientDetails) { 40 | final MongoClientDetails mongoClientDetails = new MongoClientDetails(clientDetails.getClientId(), 41 | passwordEncoder.encode(clientDetails.getClientSecret()), 42 | clientDetails.getScope(), 43 | clientDetails.getResourceIds(), 44 | clientDetails.getAuthorizedGrantTypes(), 45 | clientDetails.getRegisteredRedirectUri(), 46 | newArrayList(clientDetails.getAuthorities()), 47 | clientDetails.getAccessTokenValiditySeconds(), 48 | clientDetails.getRefreshTokenValiditySeconds(), 49 | clientDetails.getAdditionalInformation(), 50 | getAutoApproveScopes(clientDetails)); 51 | 52 | mongoClientDetailsRepository.save(mongoClientDetails); 53 | } 54 | 55 | @Override 56 | public void updateClientDetails(final ClientDetails clientDetails) { 57 | final MongoClientDetails mongoClientDetails = new MongoClientDetails(clientDetails.getClientId(), 58 | clientDetails.getClientSecret(), 59 | clientDetails.getScope(), 60 | clientDetails.getResourceIds(), 61 | clientDetails.getAuthorizedGrantTypes(), 62 | clientDetails.getRegisteredRedirectUri(), 63 | newArrayList(clientDetails.getAuthorities()), 64 | clientDetails.getAccessTokenValiditySeconds(), 65 | clientDetails.getRefreshTokenValiditySeconds(), 66 | clientDetails.getAdditionalInformation(), 67 | getAutoApproveScopes(clientDetails)); 68 | final boolean result = mongoClientDetailsRepository.update(mongoClientDetails); 69 | 70 | if (!result) { 71 | throw new NoSuchClientException("No such Client Id"); 72 | } 73 | } 74 | 75 | @Override 76 | public void updateClientSecret(final String clientId, 77 | final String secret) { 78 | final boolean result = mongoClientDetailsRepository.updateClientSecret(clientId, passwordEncoder.encode(secret)); 79 | if (!result) { 80 | throw new NoSuchClientException("No such client id"); 81 | } 82 | } 83 | 84 | @Override 85 | public void removeClientDetails(String clientId) { 86 | final boolean result = mongoClientDetailsRepository.deleteByClientId(clientId); 87 | if (!result) { 88 | throw new NoSuchClientException("No such client id"); 89 | } 90 | } 91 | 92 | @Override 93 | public List listClientDetails() { 94 | final List allClientDetails = mongoClientDetailsRepository.findAll(); 95 | return newArrayList(allClientDetails); 96 | } 97 | 98 | private Set getAutoApproveScopes(final ClientDetails clientDetails) { 99 | if (clientDetails.isAutoApprove("true")) { 100 | return newHashSet("true"); // all scopes autoapproved 101 | } 102 | 103 | return clientDetails.getScope().stream() 104 | .filter(clientDetails::isAutoApprove) 105 | .collect(Collectors.toSet()); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/MongoClientTokenServices.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import org.springframework.security.core.Authentication; 4 | import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; 5 | import org.springframework.security.oauth2.client.token.ClientKeyGenerator; 6 | import org.springframework.security.oauth2.client.token.ClientTokenServices; 7 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 8 | import org.springframework.security.oauth2.common.util.SerializationUtils; 9 | import org.springframework.stereotype.Component; 10 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2ClientToken; 11 | import uk.co.caeldev.springsecuritymongo.repositories.MongoOAuth2ClientTokenRepository; 12 | 13 | import java.util.UUID; 14 | 15 | @Component 16 | public class MongoClientTokenServices implements ClientTokenServices { 17 | 18 | private final MongoOAuth2ClientTokenRepository mongoOAuth2ClientTokenRepository; 19 | 20 | private final ClientKeyGenerator clientKeyGenerator; 21 | 22 | public MongoClientTokenServices(final MongoOAuth2ClientTokenRepository mongoOAuth2ClientTokenRepository, 23 | final ClientKeyGenerator clientKeyGenerator) { 24 | this.mongoOAuth2ClientTokenRepository = mongoOAuth2ClientTokenRepository; 25 | this.clientKeyGenerator = clientKeyGenerator; 26 | } 27 | 28 | @Override 29 | public OAuth2AccessToken getAccessToken(final OAuth2ProtectedResourceDetails resource, 30 | final Authentication authentication) { 31 | final MongoOAuth2ClientToken mongoOAuth2ClientToken = mongoOAuth2ClientTokenRepository.findByAuthenticationId(clientKeyGenerator.extractKey(resource, authentication)); 32 | return SerializationUtils.deserialize(mongoOAuth2ClientToken.getToken()); 33 | } 34 | 35 | @Override 36 | public void saveAccessToken(final OAuth2ProtectedResourceDetails resource, 37 | final Authentication authentication, 38 | final OAuth2AccessToken accessToken) { 39 | removeAccessToken(resource, authentication); 40 | final MongoOAuth2ClientToken mongoOAuth2ClientToken = new MongoOAuth2ClientToken(UUID.randomUUID().toString(), 41 | accessToken.getValue(), 42 | SerializationUtils.serialize(accessToken), 43 | clientKeyGenerator.extractKey(resource, authentication), 44 | authentication.getName(), 45 | resource.getClientId()); 46 | 47 | mongoOAuth2ClientTokenRepository.save(mongoOAuth2ClientToken); 48 | } 49 | 50 | @Override 51 | public void removeAccessToken(final OAuth2ProtectedResourceDetails resource, 52 | final Authentication authentication) { 53 | mongoOAuth2ClientTokenRepository.deleteByAuthenticationId(clientKeyGenerator.extractKey(resource, authentication)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/MongoTokenStore.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 4 | import org.springframework.security.oauth2.common.OAuth2RefreshToken; 5 | import org.springframework.security.oauth2.common.util.SerializationUtils; 6 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 7 | import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator; 8 | import org.springframework.security.oauth2.provider.token.TokenStore; 9 | import org.springframework.stereotype.Component; 10 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2AccessToken; 11 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2RefreshToken; 12 | import uk.co.caeldev.springsecuritymongo.repositories.MongoOAuth2AccessTokenRepository; 13 | import uk.co.caeldev.springsecuritymongo.repositories.MongoOAuth2RefreshTokenRepository; 14 | 15 | import java.io.UnsupportedEncodingException; 16 | import java.math.BigInteger; 17 | import java.security.MessageDigest; 18 | import java.security.NoSuchAlgorithmException; 19 | import java.util.Collection; 20 | import java.util.List; 21 | import java.util.Objects; 22 | import java.util.stream.Collectors; 23 | 24 | import static java.util.Objects.nonNull; 25 | import static org.springframework.security.oauth2.common.util.SerializationUtils.deserialize; 26 | import static org.springframework.security.oauth2.common.util.SerializationUtils.serialize; 27 | 28 | @Component 29 | public class MongoTokenStore implements TokenStore { 30 | 31 | private final MongoOAuth2AccessTokenRepository mongoOAuth2AccessTokenRepository; 32 | 33 | private final MongoOAuth2RefreshTokenRepository mongoOAuth2RefreshTokenRepository; 34 | 35 | private final AuthenticationKeyGenerator authenticationKeyGenerator; 36 | 37 | public MongoTokenStore(final MongoOAuth2AccessTokenRepository mongoOAuth2AccessTokenRepository, 38 | final MongoOAuth2RefreshTokenRepository mongoOAuth2RefreshTokenRepository, 39 | final AuthenticationKeyGenerator authenticationKeyGenerator) { 40 | this.mongoOAuth2AccessTokenRepository = mongoOAuth2AccessTokenRepository; 41 | this.mongoOAuth2RefreshTokenRepository = mongoOAuth2RefreshTokenRepository; 42 | this.authenticationKeyGenerator = authenticationKeyGenerator; 43 | } 44 | 45 | @Override 46 | public OAuth2Authentication readAuthentication(final OAuth2AccessToken token) { 47 | return readAuthentication(token.getValue()); 48 | } 49 | 50 | @Override 51 | public OAuth2Authentication readAuthentication(final String token) { 52 | final String tokenId = extractTokenKey(token); 53 | 54 | final MongoOAuth2AccessToken mongoOAuth2AccessToken = mongoOAuth2AccessTokenRepository.findByTokenId(tokenId); 55 | 56 | if (nonNull(mongoOAuth2AccessToken)) { 57 | try { 58 | return deserializeAuthentication(mongoOAuth2AccessToken.getAuthentication()); 59 | } catch (IllegalArgumentException e) { 60 | removeAccessToken(token); 61 | } 62 | } 63 | 64 | return null; 65 | } 66 | 67 | @Override 68 | public void storeAccessToken(final OAuth2AccessToken token, 69 | final OAuth2Authentication authentication) { 70 | String refreshToken = null; 71 | if (nonNull(token.getRefreshToken())) { 72 | refreshToken = token.getRefreshToken().getValue(); 73 | } 74 | 75 | if (nonNull(readAccessToken(token.getValue()))) { 76 | removeAccessToken(token.getValue()); 77 | } 78 | 79 | final String tokenKey = extractTokenKey(token.getValue()); 80 | 81 | final MongoOAuth2AccessToken oAuth2AccessToken = new MongoOAuth2AccessToken(tokenKey, 82 | serializeAccessToken(token), 83 | authenticationKeyGenerator.extractKey(authentication), 84 | authentication.isClientOnly() ? null : authentication.getName(), 85 | authentication.getOAuth2Request().getClientId(), 86 | serializeAuthentication(authentication), 87 | extractTokenKey(refreshToken)); 88 | 89 | mongoOAuth2AccessTokenRepository.save(oAuth2AccessToken); 90 | } 91 | 92 | @Override 93 | public OAuth2AccessToken readAccessToken(final String tokenValue) { 94 | final String tokenKey = extractTokenKey(tokenValue); 95 | final MongoOAuth2AccessToken mongoOAuth2AccessToken = mongoOAuth2AccessTokenRepository.findByTokenId(tokenKey); 96 | if (nonNull(mongoOAuth2AccessToken)) { 97 | try { 98 | return deserializeAccessToken(mongoOAuth2AccessToken.getToken()); 99 | } catch (IllegalArgumentException e) { 100 | removeAccessToken(tokenValue); 101 | } 102 | } 103 | return null; 104 | } 105 | 106 | @Override 107 | public void removeAccessToken(final OAuth2AccessToken token) { 108 | removeAccessToken(token.getValue()); 109 | } 110 | 111 | @Override 112 | public void storeRefreshToken(final OAuth2RefreshToken refreshToken, 113 | final OAuth2Authentication oAuth2Authentication) { 114 | final String tokenKey = extractTokenKey(refreshToken.getValue()); 115 | final byte[] token = serializeRefreshToken(refreshToken); 116 | final byte[] authentication = serializeAuthentication(oAuth2Authentication); 117 | 118 | final MongoOAuth2RefreshToken oAuth2RefreshToken = new MongoOAuth2RefreshToken(tokenKey, token, authentication); 119 | 120 | mongoOAuth2RefreshTokenRepository.save(oAuth2RefreshToken); 121 | } 122 | 123 | @Override 124 | public OAuth2RefreshToken readRefreshToken(final String tokenValue) { 125 | final String tokenKey = extractTokenKey(tokenValue); 126 | final MongoOAuth2RefreshToken mongoOAuth2RefreshToken = mongoOAuth2RefreshTokenRepository.findByTokenId(tokenKey); 127 | 128 | if (nonNull(mongoOAuth2RefreshToken)) { 129 | try { 130 | return deserializeRefreshToken(mongoOAuth2RefreshToken.getToken()); 131 | } catch (IllegalArgumentException e) { 132 | removeRefreshToken(tokenValue); 133 | } 134 | } 135 | 136 | return null; 137 | } 138 | 139 | @Override 140 | public OAuth2Authentication readAuthenticationForRefreshToken(final OAuth2RefreshToken token) { 141 | return readAuthenticationForRefreshToken(token.getValue()); 142 | } 143 | 144 | @Override 145 | public void removeRefreshToken(final OAuth2RefreshToken token) { 146 | removeRefreshToken(token.getValue()); 147 | } 148 | 149 | @Override 150 | public void removeAccessTokenUsingRefreshToken(final OAuth2RefreshToken refreshToken) { 151 | removeAccessTokenUsingRefreshToken(refreshToken.getValue()); 152 | } 153 | 154 | @Override 155 | public OAuth2AccessToken getAccessToken(final OAuth2Authentication authentication) { 156 | OAuth2AccessToken accessToken = null; 157 | 158 | String key = authenticationKeyGenerator.extractKey(authentication); 159 | 160 | final MongoOAuth2AccessToken oAuth2AccessToken = mongoOAuth2AccessTokenRepository.findByAuthenticationId(key); 161 | 162 | if (oAuth2AccessToken != null) { 163 | accessToken = deserializeAccessToken(oAuth2AccessToken.getToken()); 164 | } 165 | 166 | if (accessToken != null 167 | && !key.equals(authenticationKeyGenerator.extractKey(readAuthentication(accessToken.getValue())))) { 168 | removeAccessToken(accessToken.getValue()); 169 | // Keep the store consistent (maybe the same user is represented by this authentication but the details have 170 | // changed) 171 | storeAccessToken(accessToken, authentication); 172 | } 173 | return accessToken; 174 | } 175 | 176 | @Override 177 | public Collection findTokensByClientIdAndUserName(String clientId, String userName) { 178 | final List oAuth2AccessTokens = mongoOAuth2AccessTokenRepository.findByUsernameAndClientId(userName, clientId); 179 | return transformToOAuth2AccessTokens(oAuth2AccessTokens); 180 | } 181 | 182 | @Override 183 | public Collection findTokensByClientId(final String clientId) { 184 | final List oAuth2AccessTokens = mongoOAuth2AccessTokenRepository.findByClientId(clientId); 185 | return transformToOAuth2AccessTokens(oAuth2AccessTokens); 186 | } 187 | 188 | protected String extractTokenKey(final String value) { 189 | if (Objects.isNull(value)) { 190 | return null; 191 | } 192 | MessageDigest digest; 193 | try { 194 | digest = MessageDigest.getInstance("MD5"); 195 | } 196 | catch (NoSuchAlgorithmException e) { 197 | throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK)."); 198 | } 199 | 200 | try { 201 | byte[] bytes = digest.digest(value.getBytes("UTF-8")); 202 | return String.format("%032x", new BigInteger(1, bytes)); 203 | } 204 | catch (UnsupportedEncodingException e) { 205 | throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK)."); 206 | } 207 | } 208 | 209 | protected byte[] serializeAccessToken(final OAuth2AccessToken token) { 210 | return serialize(token); 211 | } 212 | 213 | protected byte[] serializeRefreshToken(final OAuth2RefreshToken token) { 214 | return serialize(token); 215 | } 216 | 217 | protected byte[] serializeAuthentication(final OAuth2Authentication authentication) { 218 | return serialize(authentication); 219 | } 220 | 221 | protected OAuth2AccessToken deserializeAccessToken(final byte[] token) { 222 | return deserialize(token); 223 | } 224 | 225 | protected OAuth2RefreshToken deserializeRefreshToken(final byte[] token) { 226 | return deserialize(token); 227 | } 228 | 229 | protected OAuth2Authentication deserializeAuthentication(final byte[] authentication) { 230 | return deserialize(authentication); 231 | } 232 | 233 | public OAuth2Authentication readAuthenticationForRefreshToken(final String value) { 234 | final String tokenId = extractTokenKey(value); 235 | 236 | final MongoOAuth2RefreshToken mongoOAuth2RefreshToken = mongoOAuth2RefreshTokenRepository.findByTokenId(tokenId); 237 | 238 | if (nonNull(mongoOAuth2RefreshToken)) { 239 | try { 240 | return deserializeAuthentication(mongoOAuth2RefreshToken.getAuthentication()); 241 | } catch (IllegalArgumentException e) { 242 | removeRefreshToken(value); 243 | } 244 | } 245 | 246 | return null; 247 | } 248 | 249 | private void removeRefreshToken(final String token) { 250 | final String tokenId = extractTokenKey(token); 251 | mongoOAuth2RefreshTokenRepository.deleteByTokenId(tokenId); 252 | } 253 | 254 | private void removeAccessTokenUsingRefreshToken(final String refreshToken) { 255 | final String tokenId = extractTokenKey(refreshToken); 256 | mongoOAuth2AccessTokenRepository.deleteByRefreshTokenId(tokenId); 257 | 258 | } 259 | 260 | private void removeAccessToken(final String tokenValue) { 261 | final String tokenKey = extractTokenKey(tokenValue); 262 | mongoOAuth2AccessTokenRepository.deleteByTokenId(tokenKey); 263 | } 264 | 265 | private Collection transformToOAuth2AccessTokens(final List oAuth2AccessTokens) { 266 | return oAuth2AccessTokens.stream() 267 | .filter(Objects::nonNull) 268 | .map(token -> SerializationUtils.deserialize(token.getToken())) 269 | .collect(Collectors.toList()); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/MongoUserDetailsManager.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import com.google.common.collect.Sets; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.security.access.AccessDeniedException; 7 | import org.springframework.security.authentication.AuthenticationManager; 8 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.GrantedAuthority; 11 | import org.springframework.security.core.userdetails.UserDetails; 12 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 13 | import org.springframework.security.provisioning.UserDetailsManager; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.util.Assert; 16 | import uk.co.caeldev.springsecuritymongo.domain.User; 17 | import uk.co.caeldev.springsecuritymongo.repositories.UserRepository; 18 | import uk.co.caeldev.springsecuritymongo.services.SecurityContextService; 19 | 20 | import java.util.Collection; 21 | import java.util.Optional; 22 | 23 | import static java.util.Objects.isNull; 24 | import static java.util.Objects.nonNull; 25 | 26 | @Component 27 | public class MongoUserDetailsManager implements UserDetailsManager { 28 | 29 | protected final Logger logger = LoggerFactory.getLogger(getClass()); 30 | 31 | private final UserRepository userRepository; 32 | 33 | private AuthenticationManager authenticationManager; 34 | 35 | private SecurityContextService securityContextService; 36 | 37 | public MongoUserDetailsManager(final UserRepository userRepository, 38 | final SecurityContextService securityContextService, 39 | final AuthenticationManager authenticationManager) { 40 | this.userRepository = userRepository; 41 | this.securityContextService = securityContextService; 42 | this.authenticationManager = authenticationManager; 43 | } 44 | 45 | @Override 46 | public void createUser(final UserDetails user) { 47 | validateUserDetails(user); 48 | userRepository.save(getUser(user)); 49 | } 50 | 51 | private User getUser(UserDetails userDetails) { 52 | final User user = (User) userDetails; 53 | return new User(user.getPassword(), user.getUsername(), user.getUserUUID(), Sets.newConcurrentHashSet(user.getAuthorities()), user.isAccountNonExpired(), user.isAccountNonLocked(),user.isCredentialsNonExpired(), user.isEnabled()); 54 | } 55 | 56 | @Override 57 | public void updateUser(final UserDetails user) { 58 | validateUserDetails(user); 59 | userRepository.save(getUser(user)); 60 | } 61 | 62 | @Override 63 | public void deleteUser(final String username) { 64 | userRepository.deleteByUsername(username); 65 | } 66 | 67 | @Override 68 | public void changePassword(final String oldPassword, final String newPassword) { 69 | final Authentication currentUser = securityContextService.getAuthentication(); 70 | 71 | if (isNull(currentUser)) { 72 | // This would indicate bad coding somewhere 73 | throw new AccessDeniedException("Can't change password as no Authentication object found in context " + 74 | "for current user."); 75 | } 76 | 77 | final String username = currentUser.getName(); 78 | 79 | // If an authentication manager has been set, re-authenticate the user with the supplied password. 80 | if (nonNull(authenticationManager)) { 81 | logger.debug("Reauthenticating user '"+ username + "' for password change request."); 82 | 83 | authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, oldPassword)); 84 | } else { 85 | logger.debug("No authentication manager set. Password won't be re-checked."); 86 | } 87 | 88 | logger.debug("Changing password for user '"+ username + "'"); 89 | 90 | userRepository.changePassword(oldPassword, newPassword, username); 91 | 92 | securityContextService.setAuthentication(createNewAuthentication(currentUser)); 93 | } 94 | 95 | @Override 96 | public boolean userExists(final String username) { 97 | return userRepository.findByUsername(username).isPresent(); 98 | } 99 | 100 | @Override 101 | public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException { 102 | final Optional byUsername = userRepository.findByUsername(username); 103 | if (byUsername.isPresent()) { 104 | return byUsername.get(); 105 | } 106 | throw new UsernameNotFoundException("user does not exists."); 107 | } 108 | 109 | protected Authentication createNewAuthentication(final Authentication currentAuth) { 110 | final UserDetails user = loadUserByUsername(currentAuth.getName()); 111 | 112 | final UsernamePasswordAuthenticationToken newAuthentication = 113 | new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); 114 | newAuthentication.setDetails(currentAuth.getDetails()); 115 | 116 | return newAuthentication; 117 | } 118 | 119 | private void validateUserDetails(UserDetails user) { 120 | Assert.hasText(user.getUsername(), "Username may not be empty or null"); 121 | validateAuthorities(user.getAuthorities()); 122 | } 123 | 124 | private void validateAuthorities(Collection authorities) { 125 | Assert.notNull(authorities, "Authorities list must not be null"); 126 | 127 | for (GrantedAuthority authority : authorities) { 128 | Assert.notNull(authority, "Authorities list contains a null entry"); 129 | Assert.hasText(authority.getAuthority(), "getAuthority() method must return a non-empty string"); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/config/EnableSecurityMongo.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.config; 2 | 3 | import org.springframework.context.annotation.Import; 4 | 5 | import java.lang.annotation.*; 6 | 7 | @Retention(RetentionPolicy.RUNTIME) 8 | @Target(ElementType.TYPE) 9 | @Documented 10 | @Import({ MongoConfiguration.class }) 11 | public @interface EnableSecurityMongo { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/config/MongoConfiguration.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.config; 2 | 3 | import com.mongodb.MongoClient; 4 | import com.mongodb.MongoClientOptions; 5 | import com.mongodb.MongoCredential; 6 | import com.mongodb.ServerAddress; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 8 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.ComponentScan; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.context.annotation.Profile; 13 | import org.springframework.data.mongodb.core.MongoTemplate; 14 | import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; 15 | import org.springframework.security.authentication.AuthenticationManager; 16 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 17 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 18 | import org.springframework.security.crypto.password.PasswordEncoder; 19 | import org.springframework.security.oauth2.client.token.ClientKeyGenerator; 20 | import org.springframework.security.oauth2.client.token.DefaultClientKeyGenerator; 21 | import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator; 22 | import org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator; 23 | import uk.co.caeldev.springsecuritymongo.services.SecurityContextService; 24 | 25 | @Configuration 26 | @EnableConfigurationProperties(MongoSettings.class) 27 | @ComponentScan(basePackages = {"uk.co.caeldev.springsecuritymongo"}) 28 | @EnableMongoRepositories(basePackages = {"uk.co.caeldev.springsecuritymongo.repositories"}) 29 | public class MongoConfiguration { 30 | 31 | @Bean 32 | public MongoTemplate mongoTemplate(final MongoClient mongoClient, 33 | final MongoSettings mongoSettings) { 34 | return new MongoTemplate(mongoClient, mongoSettings.getDatabase()); 35 | } 36 | 37 | @Configuration 38 | @EnableConfigurationProperties(MongoSettings.class) 39 | @ConditionalOnProperty({ 40 | "mongo.host", 41 | "mongo.port", 42 | "mongo.database", 43 | "mongo.username", 44 | "mongo.password"}) 45 | @Profile("!test") 46 | static class MongoClientConfiguration { 47 | 48 | @Bean 49 | public MongoClient mongoClient(final MongoSettings mongoSettings) { 50 | ServerAddress serverAddress = new ServerAddress( 51 | mongoSettings.getHost(), mongoSettings.getPort()); 52 | 53 | MongoCredential credential = MongoCredential.createCredential( 54 | mongoSettings.getUsername(), 55 | mongoSettings.getDatabase(), 56 | mongoSettings.getPassword().toCharArray()); 57 | 58 | return new MongoClient( 59 | serverAddress, credential, new MongoClientOptions.Builder().build()); 60 | } 61 | } 62 | 63 | @Configuration 64 | static class SecurityConfig extends WebSecurityConfigurerAdapter { 65 | 66 | @Bean 67 | @Override 68 | public AuthenticationManager authenticationManagerBean() throws Exception { 69 | return super.authenticationManagerBean(); 70 | } 71 | 72 | } 73 | 74 | @Configuration 75 | static class SpringSecurityConfiguration { 76 | 77 | @Bean 78 | public SecurityContextService securityContextService() { 79 | return new SecurityContextService(); 80 | } 81 | 82 | @Bean 83 | public AuthenticationKeyGenerator authenticationKeyGenerator() { 84 | return new DefaultAuthenticationKeyGenerator(); 85 | } 86 | 87 | @Bean 88 | public PasswordEncoder passwordEncoder() { 89 | return new BCryptPasswordEncoder(); 90 | } 91 | 92 | @Bean 93 | public ClientKeyGenerator clientKeyGenerator(){ 94 | return new DefaultClientKeyGenerator(); 95 | } 96 | 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/config/MongoSettings.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | @ConfigurationProperties(prefix="mongo") 8 | public class MongoSettings { 9 | 10 | private String host; 11 | 12 | private int port; 13 | 14 | private String database; 15 | 16 | private String username; 17 | 18 | private String password; 19 | 20 | public String getHost() { 21 | return host; 22 | } 23 | 24 | public void setHost(String host) { 25 | this.host = host; 26 | } 27 | 28 | public int getPort() { 29 | return port; 30 | } 31 | 32 | public void setPort(int port) { 33 | this.port = port; 34 | } 35 | 36 | public String getDatabase() { 37 | return database; 38 | } 39 | 40 | public void setDatabase(String database) { 41 | this.database = database; 42 | } 43 | 44 | public String getUsername() { 45 | return username; 46 | } 47 | 48 | public void setUsername(String username) { 49 | this.username = username; 50 | } 51 | 52 | public String getPassword() { 53 | return password; 54 | } 55 | 56 | public void setPassword(String password) { 57 | this.password = password; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/domain/MongoApproval.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.domain; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.annotation.PersistenceConstructor; 5 | import org.springframework.data.mongodb.core.mapping.Document; 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus; 8 | 9 | import java.time.LocalDateTime; 10 | import java.util.Objects; 11 | 12 | @Document 13 | public class MongoApproval { 14 | 15 | @Id 16 | private String id; 17 | private String userId; 18 | private String clientId; 19 | private String scope; 20 | private ApprovalStatus status; 21 | private LocalDateTime expiresAt; 22 | private LocalDateTime lastUpdatedAt; 23 | 24 | public MongoApproval() { 25 | } 26 | 27 | @PersistenceConstructor 28 | public MongoApproval(final String id, 29 | final String userId, 30 | final String clientId, 31 | final String scope, 32 | final ApprovalStatus status, 33 | final LocalDateTime expiresAt, 34 | final LocalDateTime lastUpdatedAt) { 35 | this.id = id; 36 | this.userId = userId; 37 | this.clientId = clientId; 38 | this.scope = scope; 39 | this.status = status; 40 | this.expiresAt = expiresAt; 41 | this.lastUpdatedAt = lastUpdatedAt; 42 | } 43 | 44 | public String getId() { 45 | return id; 46 | } 47 | 48 | public String getUserId() { 49 | return userId; 50 | } 51 | 52 | public String getClientId() { 53 | return clientId; 54 | } 55 | 56 | public String getScope() { 57 | return scope; 58 | } 59 | 60 | public ApprovalStatus getStatus() { 61 | return status; 62 | } 63 | 64 | @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) 65 | public LocalDateTime getExpiresAt() { 66 | return expiresAt; 67 | } 68 | 69 | @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) 70 | public LocalDateTime getLastUpdatedAt() { 71 | return lastUpdatedAt; 72 | } 73 | 74 | @Override 75 | public int hashCode() { 76 | return Objects.hash(userId, clientId, scope, status, expiresAt, lastUpdatedAt); 77 | } 78 | 79 | @Override 80 | public boolean equals(Object obj) { 81 | if (this == obj) { 82 | return true; 83 | } 84 | if (obj == null || getClass() != obj.getClass()) { 85 | return false; 86 | } 87 | final MongoApproval other = (MongoApproval) obj; 88 | return Objects.equals(this.userId, other.userId) 89 | && Objects.equals(this.clientId, other.clientId) 90 | && Objects.equals(this.scope, other.scope) 91 | && Objects.equals(this.status, other.status) 92 | && Objects.equals(this.expiresAt, other.expiresAt) 93 | && Objects.equals(this.lastUpdatedAt, other.lastUpdatedAt); 94 | } 95 | 96 | @Override 97 | public String toString() { 98 | return "MongoApproval{" + 99 | "id='" + id + '\'' + 100 | ", userId='" + userId + '\'' + 101 | ", clientId='" + clientId + '\'' + 102 | ", scope='" + scope + '\'' + 103 | ", status=" + status + 104 | ", expiresAt=" + expiresAt + 105 | ", lastUpdatedAt=" + lastUpdatedAt + 106 | '}'; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/domain/MongoClientDetails.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.domain; 2 | 3 | import org.apache.commons.lang3.builder.EqualsBuilder; 4 | import org.apache.commons.lang3.builder.HashCodeBuilder; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | import org.springframework.data.annotation.Id; 7 | import org.springframework.data.annotation.PersistenceConstructor; 8 | import org.springframework.data.mongodb.core.mapping.Document; 9 | import org.springframework.security.core.GrantedAuthority; 10 | import org.springframework.security.oauth2.provider.ClientDetails; 11 | 12 | import java.util.*; 13 | 14 | import static java.util.Objects.isNull; 15 | 16 | @Document 17 | public class MongoClientDetails implements ClientDetails { 18 | 19 | @Id 20 | private String clientId; 21 | private String clientSecret; 22 | private Set scope = Collections.emptySet(); 23 | private Set resourceIds = Collections.emptySet(); 24 | private Set authorizedGrantTypes = Collections.emptySet(); 25 | private Set registeredRedirectUris; 26 | private List authorities = Collections.emptyList(); 27 | private Integer accessTokenValiditySeconds; 28 | private Integer refreshTokenValiditySeconds; 29 | private Map additionalInformation = new LinkedHashMap<>(); 30 | private Set autoApproveScopes; 31 | 32 | public MongoClientDetails() { 33 | } 34 | 35 | @PersistenceConstructor 36 | public MongoClientDetails(final String clientId, 37 | final String clientSecret, 38 | final Set scope, 39 | final Set resourceIds, 40 | final Set authorizedGrantTypes, 41 | final Set registeredRedirectUris, 42 | final List authorities, 43 | final Integer accessTokenValiditySeconds, 44 | final Integer refreshTokenValiditySeconds, 45 | final Map additionalInformation, 46 | final Set autoApproveScopes) { 47 | this.clientId = clientId; 48 | this.clientSecret = clientSecret; 49 | this.scope = scope; 50 | this.resourceIds = resourceIds; 51 | this.authorizedGrantTypes = authorizedGrantTypes; 52 | this.registeredRedirectUris = registeredRedirectUris; 53 | this.authorities = authorities; 54 | this.accessTokenValiditySeconds = accessTokenValiditySeconds; 55 | this.refreshTokenValiditySeconds = refreshTokenValiditySeconds; 56 | this.additionalInformation = additionalInformation; 57 | this.autoApproveScopes = autoApproveScopes; 58 | } 59 | 60 | public String getClientId() { 61 | return clientId; 62 | } 63 | 64 | public String getClientSecret() { 65 | return clientSecret; 66 | } 67 | 68 | public Set getScope() { 69 | return scope; 70 | } 71 | 72 | public Set getResourceIds() { 73 | return resourceIds; 74 | } 75 | 76 | public Set getAuthorizedGrantTypes() { 77 | return authorizedGrantTypes; 78 | } 79 | 80 | public List getAuthorities() { 81 | return authorities; 82 | } 83 | 84 | public Integer getAccessTokenValiditySeconds() { 85 | return accessTokenValiditySeconds; 86 | } 87 | 88 | public Integer getRefreshTokenValiditySeconds() { 89 | return refreshTokenValiditySeconds; 90 | } 91 | 92 | public Map getAdditionalInformation() { 93 | return additionalInformation; 94 | } 95 | 96 | public void setAutoApproveScopes(final Set autoApproveScopes) { 97 | this.autoApproveScopes = autoApproveScopes; 98 | } 99 | 100 | public Set getAutoApproveScopes() { 101 | return autoApproveScopes; 102 | } 103 | 104 | @Override 105 | public boolean isScoped() { 106 | return this.scope != null && !this.scope.isEmpty(); 107 | } 108 | 109 | @Override 110 | public boolean isSecretRequired() { 111 | return this.clientSecret != null; 112 | } 113 | 114 | @Override 115 | public Set getRegisteredRedirectUri() { 116 | return registeredRedirectUris; 117 | } 118 | 119 | @Override 120 | public boolean isAutoApprove(final String scope) { 121 | if (isNull(autoApproveScopes)) { 122 | return false; 123 | } 124 | for (String auto : autoApproveScopes) { 125 | if ("true".equals(auto) || scope.matches(auto)) { 126 | return true; 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | @Override 133 | public boolean equals(Object o) { 134 | if (this == o) return true; 135 | 136 | if (!(o instanceof MongoClientDetails)) return false; 137 | 138 | MongoClientDetails that = (MongoClientDetails) o; 139 | 140 | return new EqualsBuilder() 141 | .append(clientId, that.clientId) 142 | .append(scope, that.scope) 143 | .append(resourceIds, that.resourceIds) 144 | .append(authorizedGrantTypes, that.authorizedGrantTypes) 145 | .append(registeredRedirectUris, that.registeredRedirectUris) 146 | .append(authorities, that.authorities) 147 | .append(accessTokenValiditySeconds, that.accessTokenValiditySeconds) 148 | .append(refreshTokenValiditySeconds, that.refreshTokenValiditySeconds) 149 | .append(additionalInformation, that.additionalInformation) 150 | .append(autoApproveScopes, that.autoApproveScopes) 151 | .isEquals(); 152 | } 153 | 154 | @Override 155 | public int hashCode() { 156 | return new HashCodeBuilder(17, 37) 157 | .append(clientId) 158 | .append(clientSecret) 159 | .append(scope) 160 | .append(resourceIds) 161 | .append(authorizedGrantTypes) 162 | .append(registeredRedirectUris) 163 | .append(authorities) 164 | .append(accessTokenValiditySeconds) 165 | .append(refreshTokenValiditySeconds) 166 | .append(additionalInformation) 167 | .append(autoApproveScopes) 168 | .toHashCode(); 169 | } 170 | 171 | @Override 172 | public String toString() { 173 | return new ToStringBuilder(this) 174 | .append("clientId", clientId) 175 | .append("clientSecret", clientSecret) 176 | .append("scope", scope) 177 | .append("resourceIds", resourceIds) 178 | .append("authorizedGrantTypes", authorizedGrantTypes) 179 | .append("registeredRedirectUris", registeredRedirectUris) 180 | .append("authorities", authorities) 181 | .append("accessTokenValiditySeconds", accessTokenValiditySeconds) 182 | .append("refreshTokenValiditySeconds", refreshTokenValiditySeconds) 183 | .append("additionalInformation", additionalInformation) 184 | .append("autoApproveScopes", autoApproveScopes) 185 | .toString(); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/domain/MongoOAuth2AccessToken.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.domain; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.annotation.PersistenceConstructor; 5 | import org.springframework.data.mongodb.core.mapping.Document; 6 | 7 | import java.util.Arrays; 8 | import java.util.Objects; 9 | 10 | @Document 11 | public class MongoOAuth2AccessToken { 12 | 13 | @Id 14 | private String tokenId; 15 | private byte[] token; 16 | private String authenticationId; 17 | private String username; 18 | private String clientId; 19 | private byte[] authentication; 20 | private String refreshToken; 21 | 22 | public MongoOAuth2AccessToken() { 23 | } 24 | 25 | @PersistenceConstructor 26 | public MongoOAuth2AccessToken(final String tokenId, 27 | final byte[] token, 28 | final String authenticationId, 29 | final String username, 30 | final String clientId, 31 | final byte[] authentication, 32 | final String refreshToken) { 33 | this.tokenId = tokenId; 34 | this.token = token; 35 | this.authenticationId = authenticationId; 36 | this.username = username; 37 | this.clientId = clientId; 38 | this.authentication = authentication; 39 | this.refreshToken = refreshToken; 40 | } 41 | 42 | public String getTokenId() { 43 | return tokenId; 44 | } 45 | 46 | public byte[] getToken() { 47 | return token; 48 | } 49 | 50 | public String getAuthenticationId() { 51 | return authenticationId; 52 | } 53 | 54 | public String getUsername() { 55 | return username; 56 | } 57 | 58 | public String getClientId() { 59 | return clientId; 60 | } 61 | 62 | public byte[] getAuthentication() { 63 | return authentication; 64 | } 65 | 66 | public String getRefreshToken() { 67 | return refreshToken; 68 | } 69 | 70 | @Override 71 | public int hashCode() { 72 | return Objects.hash(token, authenticationId, username, clientId, authentication, refreshToken); 73 | } 74 | 75 | @Override 76 | public boolean equals(Object obj) { 77 | if (this == obj) { 78 | return true; 79 | } 80 | if (obj == null || getClass() != obj.getClass()) { 81 | return false; 82 | } 83 | final MongoOAuth2AccessToken other = (MongoOAuth2AccessToken) obj; 84 | return Objects.equals(this.token, other.token) && Objects.equals(this.authenticationId, other.authenticationId) && Objects.equals(this.username, other.username) && Objects.equals(this.clientId, other.clientId) && Objects.equals(this.authentication, other.authentication) && Objects.equals(this.refreshToken, other.refreshToken); 85 | } 86 | 87 | @Override 88 | public String toString() { 89 | return "MongoOAuth2AccessToken{" + 90 | "tokenId='" + tokenId + '\'' + 91 | ", token=" + Arrays.toString(token) + 92 | ", authenticationId='" + authenticationId + '\'' + 93 | ", username='" + username + '\'' + 94 | ", clientId='" + clientId + '\'' + 95 | ", authentication=" + Arrays.toString(authentication) + 96 | ", refreshToken='" + refreshToken + '\'' + 97 | '}'; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/domain/MongoOAuth2ClientToken.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.domain; 2 | 3 | import org.apache.commons.lang3.builder.EqualsBuilder; 4 | import org.apache.commons.lang3.builder.HashCodeBuilder; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | import org.springframework.data.annotation.Id; 7 | import org.springframework.data.annotation.PersistenceConstructor; 8 | import org.springframework.data.mongodb.core.mapping.Document; 9 | 10 | @Document 11 | public class MongoOAuth2ClientToken { 12 | 13 | @Id 14 | private String id; 15 | private String tokenId; 16 | private byte[] token; 17 | private String authenticationId; 18 | private String username; 19 | private String clientId; 20 | 21 | public MongoOAuth2ClientToken() { 22 | } 23 | 24 | @PersistenceConstructor 25 | public MongoOAuth2ClientToken(final String id, 26 | final String tokenId, 27 | final byte[] token, 28 | final String authenticationId, 29 | final String username, 30 | final String clientId) { 31 | this.id = id; 32 | this.tokenId = tokenId; 33 | this.token = token; 34 | this.authenticationId = authenticationId; 35 | this.username = username; 36 | this.clientId = clientId; 37 | } 38 | 39 | public String getId() { 40 | return id; 41 | } 42 | 43 | public String getTokenId() { 44 | return tokenId; 45 | } 46 | 47 | public byte[] getToken() { 48 | return token; 49 | } 50 | 51 | public String getAuthenticationId() { 52 | return authenticationId; 53 | } 54 | 55 | public String getUsername() { 56 | return username; 57 | } 58 | 59 | public String getClientId() { 60 | return clientId; 61 | } 62 | 63 | @Override 64 | public boolean equals(Object o) { 65 | if (this == o) return true; 66 | 67 | if (!(o instanceof MongoOAuth2ClientToken)) return false; 68 | 69 | MongoOAuth2ClientToken that = (MongoOAuth2ClientToken) o; 70 | 71 | return new EqualsBuilder() 72 | .append(id, that.id) 73 | .append(tokenId, that.tokenId) 74 | .append(token, that.token) 75 | .append(authenticationId, that.authenticationId) 76 | .append(username, that.username) 77 | .append(clientId, that.clientId) 78 | .isEquals(); 79 | } 80 | 81 | @Override 82 | public int hashCode() { 83 | return new HashCodeBuilder(17, 37) 84 | .append(id) 85 | .append(tokenId) 86 | .append(token) 87 | .append(authenticationId) 88 | .append(username) 89 | .append(clientId) 90 | .toHashCode(); 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return new ToStringBuilder(this) 96 | .append("id", id) 97 | .append("tokenId", tokenId) 98 | .append("token", token) 99 | .append("authenticationId", authenticationId) 100 | .append("username", username) 101 | .append("clientId", clientId) 102 | .toString(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/domain/MongoOAuth2RefreshToken.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.domain; 2 | 3 | import org.apache.commons.lang3.builder.EqualsBuilder; 4 | import org.apache.commons.lang3.builder.HashCodeBuilder; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | import org.springframework.data.annotation.Id; 7 | import org.springframework.data.annotation.PersistenceConstructor; 8 | import org.springframework.data.mongodb.core.mapping.Document; 9 | 10 | @Document 11 | public class MongoOAuth2RefreshToken { 12 | 13 | @Id 14 | private String tokenId; 15 | private byte[] token; 16 | private byte[] authentication; 17 | 18 | public MongoOAuth2RefreshToken() { 19 | } 20 | 21 | @PersistenceConstructor 22 | public MongoOAuth2RefreshToken(final String tokenId, 23 | final byte[] token, 24 | final byte[] authentication) { 25 | this.tokenId = tokenId; 26 | this.token = token; 27 | this.authentication = authentication; 28 | } 29 | 30 | public String getTokenId() { 31 | return tokenId; 32 | } 33 | 34 | public byte[] getToken() { 35 | return token; 36 | } 37 | 38 | public byte[] getAuthentication() { 39 | return authentication; 40 | } 41 | 42 | @Override 43 | public boolean equals(Object o) { 44 | if (this == o) return true; 45 | 46 | if (!(o instanceof MongoOAuth2RefreshToken)) return false; 47 | 48 | MongoOAuth2RefreshToken that = (MongoOAuth2RefreshToken) o; 49 | 50 | return new EqualsBuilder() 51 | .append(tokenId, that.tokenId) 52 | .append(token, that.token) 53 | .append(authentication, that.authentication) 54 | .isEquals(); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return new HashCodeBuilder(17, 37) 60 | .append(tokenId) 61 | .append(token) 62 | .append(authentication) 63 | .toHashCode(); 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return new ToStringBuilder(this) 69 | .append("tokenId", tokenId) 70 | .append("token", token) 71 | .append("authentication", authentication) 72 | .toString(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/domain/User.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.domain; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.annotation.PersistenceConstructor; 5 | import org.springframework.data.mongodb.core.mapping.Document; 6 | import org.springframework.security.core.CredentialsContainer; 7 | import org.springframework.security.core.GrantedAuthority; 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | 10 | import java.util.Collection; 11 | import java.util.Objects; 12 | import java.util.Set; 13 | import java.util.UUID; 14 | 15 | @Document 16 | public class User implements UserDetails, CredentialsContainer { 17 | 18 | @Id 19 | private String username; 20 | private String password; 21 | private UUID userUUID; 22 | private Set authorities; 23 | private boolean accountNonExpired; 24 | private boolean accountNonLocked; 25 | private boolean credentialsNonExpired; 26 | private boolean enabled; 27 | 28 | public User() { 29 | } 30 | 31 | @PersistenceConstructor 32 | public User(final String password, 33 | final String username, 34 | final UUID userUUID, 35 | final Set authorities, 36 | final boolean accountNonExpired, 37 | final boolean accountNonLocked, 38 | final boolean credentialsNonExpired, 39 | final boolean enabled) { 40 | this.password = password; 41 | this.username = username; 42 | this.userUUID = userUUID; 43 | this.authorities = authorities; 44 | this.accountNonExpired = accountNonExpired; 45 | this.accountNonLocked = accountNonLocked; 46 | this.credentialsNonExpired = credentialsNonExpired; 47 | this.enabled = enabled; 48 | } 49 | 50 | @Override 51 | public Collection getAuthorities() { 52 | return authorities; 53 | } 54 | 55 | @Override 56 | public String getPassword() { 57 | return password; 58 | } 59 | 60 | @Override 61 | public String getUsername() { 62 | return username; 63 | } 64 | 65 | @Override 66 | public boolean isAccountNonExpired() { 67 | return accountNonExpired; 68 | } 69 | 70 | @Override 71 | public boolean isAccountNonLocked() { 72 | return accountNonLocked; 73 | } 74 | 75 | @Override 76 | public boolean isCredentialsNonExpired() { 77 | return credentialsNonExpired; 78 | } 79 | 80 | @Override 81 | public boolean isEnabled() { 82 | return enabled; 83 | } 84 | 85 | @Override 86 | public void eraseCredentials() { 87 | password = null; 88 | } 89 | 90 | public UUID getUserUUID() { 91 | return userUUID; 92 | } 93 | 94 | @Override 95 | public int hashCode() { 96 | return Objects.hash(password, username, userUUID, authorities, accountNonExpired, accountNonLocked, credentialsNonExpired, enabled); 97 | } 98 | 99 | @Override 100 | public boolean equals(Object obj) { 101 | if (this == obj) { 102 | return true; 103 | } 104 | if (obj == null || getClass() != obj.getClass()) { 105 | return false; 106 | } 107 | final User other = (User) obj; 108 | return Objects.equals(this.password, other.password) && Objects.equals(this.username, other.username) && Objects.equals(this.userUUID, other.userUUID) && Objects.equals(this.authorities, other.authorities) && Objects.equals(this.accountNonExpired, other.accountNonExpired) && Objects.equals(this.accountNonLocked, other.accountNonLocked) && Objects.equals(this.credentialsNonExpired, other.credentialsNonExpired) && Objects.equals(this.enabled, other.enabled); 109 | } 110 | 111 | @Override 112 | public String toString() { 113 | return "User{" + 114 | "username='" + username + '\'' + 115 | ", password='" + password + '\'' + 116 | ", userUUID=" + userUUID + 117 | ", authorities=" + authorities + 118 | ", accountNonExpired=" + accountNonExpired + 119 | ", accountNonLocked=" + accountNonLocked + 120 | ", credentialsNonExpired=" + credentialsNonExpired + 121 | ", enabled=" + enabled + 122 | '}'; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoApprovalRepository.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import org.springframework.data.mongodb.repository.MongoRepository; 4 | import uk.co.caeldev.springsecuritymongo.domain.MongoApproval; 5 | 6 | public interface MongoApprovalRepository extends MongoRepository, MongoApprovalRepositoryBase { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoApprovalRepositoryBase.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import uk.co.caeldev.springsecuritymongo.domain.MongoApproval; 4 | 5 | import java.time.LocalDateTime; 6 | import java.util.Collection; 7 | import java.util.List; 8 | 9 | public interface MongoApprovalRepositoryBase { 10 | boolean updateOrCreate(Collection mongoApprovals); 11 | 12 | boolean updateExpiresAt(LocalDateTime now, MongoApproval mongoApproval); 13 | 14 | boolean deleteByUserIdAndClientIdAndScope(MongoApproval mongoApproval); 15 | 16 | List findByUserIdAndClientId(String userId, String clientId); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoApprovalRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.mongodb.client.result.DeleteResult; 4 | import com.mongodb.client.result.UpdateResult; 5 | import org.springframework.data.mongodb.core.MongoTemplate; 6 | import org.springframework.data.mongodb.core.query.Query; 7 | import org.springframework.data.mongodb.core.query.Update; 8 | import org.springframework.stereotype.Component; 9 | import uk.co.caeldev.springsecuritymongo.domain.MongoApproval; 10 | 11 | import java.time.LocalDateTime; 12 | import java.util.Collection; 13 | import java.util.List; 14 | 15 | import static org.springframework.data.mongodb.core.query.Criteria.where; 16 | 17 | @Component 18 | public class MongoApprovalRepositoryImpl implements MongoApprovalRepositoryBase { 19 | 20 | private final MongoTemplate mongoTemplate; 21 | 22 | public MongoApprovalRepositoryImpl(final MongoTemplate mongoTemplate) { 23 | this.mongoTemplate = mongoTemplate; 24 | } 25 | 26 | @Override 27 | public boolean updateOrCreate(final Collection mongoApprovals) { 28 | boolean result = true; 29 | for (MongoApproval mongoApproval : mongoApprovals) { 30 | final Update update = Update.update("expiresAt", mongoApproval.getExpiresAt()) 31 | .set("status", mongoApproval.getStatus()) 32 | .set("lastUpdatedAt", mongoApproval.getLastUpdatedAt()); 33 | 34 | final UpdateResult upsert = mongoTemplate.upsert(byUserIdAndClientIdAndScope(mongoApproval), update, MongoApproval.class); 35 | 36 | if (!upsert.wasAcknowledged()) { 37 | result = false; 38 | } 39 | } 40 | return result; 41 | } 42 | 43 | @Override 44 | public boolean updateExpiresAt(final LocalDateTime expiresAt, 45 | final MongoApproval mongoApproval) { 46 | final Update update = Update.update("expiresAt", expiresAt); 47 | 48 | final UpdateResult updateResult = mongoTemplate.updateFirst(byUserIdAndClientIdAndScope(mongoApproval), 49 | update, 50 | MongoApproval.class); 51 | 52 | return updateResult.wasAcknowledged(); 53 | } 54 | 55 | @Override 56 | public boolean deleteByUserIdAndClientIdAndScope(final MongoApproval mongoApproval) { 57 | final DeleteResult deleteResult = mongoTemplate.remove(byUserIdAndClientIdAndScope(mongoApproval), 58 | MongoApproval.class); 59 | 60 | return deleteResult.wasAcknowledged(); 61 | } 62 | 63 | @Override 64 | public List findByUserIdAndClientId(final String userId, 65 | final String clientId) { 66 | final Query query = Query.query(where("userId").is(userId) 67 | .andOperator(where("clientId").is(clientId))); 68 | return mongoTemplate.find(query, MongoApproval.class); 69 | } 70 | 71 | private Query byUserIdAndClientIdAndScope(final MongoApproval mongoApproval) { 72 | return Query.query(where("userId").is(mongoApproval.getUserId()) 73 | .andOperator(where("clientId").is(mongoApproval.getClientId()) 74 | .andOperator(where("scope").is(mongoApproval.getScope())))); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoClientDetailsRepository.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import org.springframework.data.mongodb.repository.MongoRepository; 4 | import uk.co.caeldev.springsecuritymongo.domain.MongoClientDetails; 5 | 6 | public interface MongoClientDetailsRepository extends MongoRepository, MongoClientDetailsRepositoryBase { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoClientDetailsRepositoryBase.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import uk.co.caeldev.springsecuritymongo.domain.MongoClientDetails; 4 | 5 | public interface MongoClientDetailsRepositoryBase { 6 | boolean deleteByClientId(String clientId); 7 | 8 | boolean update(MongoClientDetails mongoClientDetails); 9 | 10 | boolean updateClientSecret(String clientId, String newSecret); 11 | 12 | MongoClientDetails findByClientId(String clientId); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoClientDetailsRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.mongodb.client.result.DeleteResult; 4 | import com.mongodb.client.result.UpdateResult; 5 | import org.springframework.data.mongodb.core.MongoTemplate; 6 | import org.springframework.data.mongodb.core.query.Criteria; 7 | import org.springframework.data.mongodb.core.query.Query; 8 | import org.springframework.data.mongodb.core.query.Update; 9 | import org.springframework.stereotype.Component; 10 | import uk.co.caeldev.springsecuritymongo.domain.MongoClientDetails; 11 | 12 | @Component 13 | public class MongoClientDetailsRepositoryImpl implements MongoClientDetailsRepositoryBase { 14 | 15 | public static final String ID = "_id"; 16 | public static final String CLIENT_SECRET = "clientSecret"; 17 | private final MongoTemplate mongoTemplate; 18 | 19 | public MongoClientDetailsRepositoryImpl(final MongoTemplate mongoTemplate) { 20 | this.mongoTemplate = mongoTemplate; 21 | } 22 | 23 | @Override 24 | public boolean deleteByClientId(String clientId) { 25 | final Query query = Query.query(Criteria.where(ID).is(clientId)); 26 | final DeleteResult deleteResult = mongoTemplate.remove(query, MongoClientDetails.class); 27 | return deleteResult.wasAcknowledged(); 28 | } 29 | 30 | @Override 31 | public boolean update(final MongoClientDetails mongoClientDetails) { 32 | final Query query = Query.query(Criteria.where(ID).is(mongoClientDetails.getClientId())); 33 | 34 | final Update update = Update.update("scope", mongoClientDetails.getScope()) 35 | .set("resourceIds", mongoClientDetails.getResourceIds()) 36 | .set("authorizedGrantTypes", mongoClientDetails.getAuthorizedGrantTypes()) 37 | .set("authorities", mongoClientDetails.getAuthorities()) 38 | .set("accessTokenValiditySeconds", mongoClientDetails.getAccessTokenValiditySeconds()) 39 | .set("refreshTokenValiditySeconds", mongoClientDetails.getRefreshTokenValiditySeconds()) 40 | .set("additionalInformation", mongoClientDetails.getAdditionalInformation()) 41 | .set("autoApproveScopes", mongoClientDetails.getAutoApproveScopes()) 42 | .set("registeredRedirectUris", mongoClientDetails.getRegisteredRedirectUri()); 43 | 44 | final UpdateResult updateResult = mongoTemplate.updateFirst(query, update, MongoClientDetails.class); 45 | 46 | return updateResult.wasAcknowledged(); 47 | } 48 | 49 | @Override 50 | public boolean updateClientSecret(final String clientId, 51 | final String newSecret) { 52 | final Query query = Query.query(Criteria.where(ID).is(clientId)); 53 | 54 | final Update update = Update.update(CLIENT_SECRET, newSecret); 55 | 56 | final UpdateResult updateResult = mongoTemplate.updateFirst(query, update, MongoClientDetails.class); 57 | 58 | return updateResult.wasAcknowledged(); 59 | } 60 | 61 | @Override 62 | public MongoClientDetails findByClientId(final String clientId) { 63 | final Query query = Query.query(Criteria.where(ID).is(clientId)); 64 | final MongoClientDetails mongoClientDetails = mongoTemplate.findOne(query, MongoClientDetails.class); 65 | if (mongoClientDetails == null) { 66 | throw new IllegalArgumentException("No valid client id"); 67 | } 68 | return mongoClientDetails; 69 | } 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2AccessTokenRepository.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import org.springframework.data.mongodb.repository.MongoRepository; 4 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2AccessToken; 5 | 6 | public interface MongoOAuth2AccessTokenRepository extends MongoRepository, MongoOAuth2AccessTokenRepositoryBase { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2AccessTokenRepositoryBase.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2AccessToken; 4 | 5 | import java.util.List; 6 | 7 | public interface MongoOAuth2AccessTokenRepositoryBase { 8 | MongoOAuth2AccessToken findByTokenId(String tokenId); 9 | 10 | boolean deleteByTokenId(String tokenId); 11 | 12 | boolean deleteByRefreshTokenId(String refreshTokenId); 13 | 14 | MongoOAuth2AccessToken findByAuthenticationId(String key); 15 | 16 | List findByUsernameAndClientId(String username, String clientId); 17 | 18 | List findByClientId(String clientId); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2AccessTokenRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.mongodb.client.result.DeleteResult; 4 | import org.springframework.data.mongodb.core.MongoTemplate; 5 | import org.springframework.data.mongodb.core.query.Criteria; 6 | import org.springframework.data.mongodb.core.query.Query; 7 | import org.springframework.stereotype.Component; 8 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2AccessToken; 9 | 10 | import java.util.List; 11 | 12 | @Component 13 | public class MongoOAuth2AccessTokenRepositoryImpl implements MongoOAuth2AccessTokenRepositoryBase { 14 | 15 | public static final String ID = "_id"; 16 | private final MongoTemplate mongoTemplate; 17 | 18 | public MongoOAuth2AccessTokenRepositoryImpl(final MongoTemplate mongoTemplate) { 19 | this.mongoTemplate = mongoTemplate; 20 | } 21 | 22 | @Override 23 | public MongoOAuth2AccessToken findByTokenId(final String tokenId) { 24 | final Query query = Query.query(Criteria.where(ID).is(tokenId)); 25 | return mongoTemplate.findOne(query, MongoOAuth2AccessToken.class); 26 | } 27 | 28 | @Override 29 | public boolean deleteByTokenId(final String tokenId) { 30 | final Query query = Query.query(Criteria.where(ID).is(tokenId)); 31 | final DeleteResult deleteResult = mongoTemplate.remove(query, MongoOAuth2AccessToken.class); 32 | return deleteResult.wasAcknowledged(); 33 | } 34 | 35 | @Override 36 | public boolean deleteByRefreshTokenId(String refreshTokenId) { 37 | final Query query = Query.query(Criteria.where("refreshToken").is(refreshTokenId)); 38 | final DeleteResult deleteResult = mongoTemplate.remove(query, MongoOAuth2AccessToken.class); 39 | return deleteResult.wasAcknowledged(); 40 | } 41 | 42 | @Override 43 | public MongoOAuth2AccessToken findByAuthenticationId(String key) { 44 | final Query query = Query.query(Criteria.where("authenticationId").is(key)); 45 | return mongoTemplate.findOne(query, MongoOAuth2AccessToken.class); 46 | } 47 | 48 | @Override 49 | public List findByUsernameAndClientId(final String username, 50 | final String clientId) { 51 | final Query query = Query.query(Criteria.where("username").is(username).andOperator(Criteria.where("clientId").is(clientId))); 52 | return mongoTemplate.find(query, MongoOAuth2AccessToken.class); 53 | } 54 | 55 | @Override 56 | public List findByClientId(final String clientId) { 57 | final Query query = Query.query(Criteria.where("clientId").is(clientId)); 58 | return mongoTemplate.find(query, MongoOAuth2AccessToken.class); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2ClientTokenRepository.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import org.springframework.data.mongodb.repository.MongoRepository; 4 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2ClientToken; 5 | 6 | public interface MongoOAuth2ClientTokenRepository extends MongoRepository, MongoOAuth2ClientTokenRepositoryBase { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2ClientTokenRepositoryBase.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2ClientToken; 4 | 5 | public interface MongoOAuth2ClientTokenRepositoryBase { 6 | boolean deleteByAuthenticationId(String authenticationId); 7 | 8 | MongoOAuth2ClientToken findByAuthenticationId(String authenticationId); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2ClientTokenRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.mongodb.client.result.DeleteResult; 4 | import org.springframework.data.mongodb.core.MongoTemplate; 5 | import org.springframework.data.mongodb.core.query.Criteria; 6 | import org.springframework.data.mongodb.core.query.Query; 7 | import org.springframework.stereotype.Component; 8 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2ClientToken; 9 | 10 | @Component 11 | public class MongoOAuth2ClientTokenRepositoryImpl implements MongoOAuth2ClientTokenRepositoryBase { 12 | 13 | private final MongoTemplate mongoTemplate; 14 | 15 | public MongoOAuth2ClientTokenRepositoryImpl(final MongoTemplate mongoTemplate) { 16 | this.mongoTemplate = mongoTemplate; 17 | } 18 | 19 | @Override 20 | public boolean deleteByAuthenticationId(final String authenticationId) { 21 | final Query query = Query.query(Criteria.where("authenticationId").is(authenticationId)); 22 | final DeleteResult deleteResult = mongoTemplate.remove(query, MongoOAuth2ClientToken.class); 23 | return deleteResult.wasAcknowledged(); 24 | } 25 | 26 | @Override 27 | public MongoOAuth2ClientToken findByAuthenticationId(final String authenticationId) { 28 | final Query query = Query.query(Criteria.where("authenticationId").is(authenticationId)); 29 | return mongoTemplate.findOne(query, MongoOAuth2ClientToken.class); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2RefreshTokenRepository.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | 4 | import org.springframework.data.mongodb.repository.MongoRepository; 5 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2RefreshToken; 6 | 7 | public interface MongoOAuth2RefreshTokenRepository extends MongoRepository, MongoOAuth2RefreshTokenRepositoryBase { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2RefreshTokenRepositoryBase.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2RefreshToken; 4 | 5 | public interface MongoOAuth2RefreshTokenRepositoryBase { 6 | MongoOAuth2RefreshToken findByTokenId(String tokenId); 7 | 8 | boolean deleteByTokenId(String tokenId); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2RefreshTokenRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.mongodb.client.result.DeleteResult; 4 | import org.springframework.data.mongodb.core.MongoTemplate; 5 | import org.springframework.data.mongodb.core.query.Criteria; 6 | import org.springframework.data.mongodb.core.query.Query; 7 | import org.springframework.stereotype.Component; 8 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2RefreshToken; 9 | 10 | @Component 11 | public class MongoOAuth2RefreshTokenRepositoryImpl implements MongoOAuth2RefreshTokenRepositoryBase { 12 | 13 | public static final String ID = "_id"; 14 | private MongoTemplate mongoTemplate; 15 | 16 | public MongoOAuth2RefreshTokenRepositoryImpl(final MongoTemplate mongoTemplate) { 17 | this.mongoTemplate = mongoTemplate; 18 | } 19 | 20 | @Override 21 | public MongoOAuth2RefreshToken findByTokenId(final String tokenId) { 22 | final Query query = Query.query(Criteria.where(ID).is(tokenId)); 23 | return mongoTemplate.findOne(query, MongoOAuth2RefreshToken.class); 24 | } 25 | 26 | @Override 27 | public boolean deleteByTokenId(final String tokenId) { 28 | final Query query = Query.query(Criteria.where(ID).is(tokenId)); 29 | final DeleteResult deleteResult = mongoTemplate.remove(query, MongoOAuth2RefreshToken.class); 30 | return deleteResult.wasAcknowledged(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/UserRepository.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import org.springframework.data.mongodb.repository.MongoRepository; 4 | import uk.co.caeldev.springsecuritymongo.domain.User; 5 | 6 | import java.util.Optional; 7 | 8 | public interface UserRepository extends MongoRepository, UserRepositoryBase { 9 | 10 | void deleteByUsername(String username); 11 | 12 | Optional findByUsername(String username); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/UserRepositoryBase.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | public interface UserRepositoryBase { 4 | 5 | boolean changePassword(String oldPassword, String newPassword, String username); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/repositories/UserRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.mongodb.client.result.UpdateResult; 4 | import org.springframework.data.mongodb.core.MongoTemplate; 5 | import org.springframework.data.mongodb.core.query.Query; 6 | import org.springframework.stereotype.Component; 7 | import uk.co.caeldev.springsecuritymongo.domain.User; 8 | 9 | import static org.springframework.data.mongodb.core.query.Criteria.where; 10 | import static org.springframework.data.mongodb.core.query.Update.update; 11 | 12 | @Component 13 | public class UserRepositoryImpl implements UserRepositoryBase { 14 | 15 | private final MongoTemplate mongoTemplate; 16 | 17 | public UserRepositoryImpl(final MongoTemplate mongoTemplate) { 18 | this.mongoTemplate = mongoTemplate; 19 | } 20 | 21 | @Override 22 | public boolean changePassword(final String oldPassword, 23 | final String newPassword, 24 | final String username) { 25 | final Query searchUserQuery = new Query(where("username").is(username).andOperator(where("password").is(oldPassword))); 26 | final UpdateResult updateResult = mongoTemplate.updateFirst(searchUserQuery, update("password", newPassword), User.class); 27 | return updateResult.wasAcknowledged(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/services/SecurityContextService.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.services; 2 | 3 | import org.springframework.security.core.Authentication; 4 | import org.springframework.security.core.context.SecurityContextHolder; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class SecurityContextService { 9 | public Authentication getAuthentication() { 10 | return SecurityContextHolder.getContext().getAuthentication(); 11 | } 12 | 13 | public void setAuthentication(final Authentication authentication) { 14 | SecurityContextHolder.getContext().setAuthentication(authentication); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/uk/co/caeldev/springsecuritymongo/util/LocalDateTimeUtil.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.util; 2 | 3 | import java.time.Instant; 4 | import java.time.LocalDateTime; 5 | import java.time.ZoneId; 6 | import java.util.Date; 7 | 8 | public final class LocalDateTimeUtil { 9 | 10 | public static Date convertToDateFrom(final LocalDateTime localDateTime) { 11 | return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); 12 | } 13 | 14 | public static LocalDateTime convertTolocalDateTimeFrom(final Date date) { 15 | return Instant.ofEpochMilli(date.getTime()) 16 | .atZone(ZoneId.systemDefault()) 17 | .toLocalDateTime(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/MongoApprovalStoreTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.Mock; 7 | import org.mockito.junit.MockitoJUnitRunner; 8 | import org.springframework.security.oauth2.provider.approval.Approval; 9 | import uk.co.caeldev.springsecuritymongo.domain.MongoApproval; 10 | import uk.co.caeldev.springsecuritymongo.repositories.MongoApprovalRepository; 11 | 12 | import java.time.LocalDateTime; 13 | import java.util.Collection; 14 | import java.util.List; 15 | 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | import static org.mockito.ArgumentMatchers.any; 18 | import static org.mockito.ArgumentMatchers.anyCollection; 19 | import static org.mockito.BDDMockito.given; 20 | import static org.mockito.Mockito.never; 21 | import static org.mockito.Mockito.verify; 22 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.*; 23 | 24 | @RunWith(MockitoJUnitRunner.class) 25 | public class MongoApprovalStoreTest { 26 | 27 | @Mock 28 | private MongoApprovalRepository mongoApprovalRepository; 29 | 30 | private MongoApprovalStore mongoApprovalStore; 31 | 32 | @Before 33 | public void setup() { 34 | mongoApprovalStore = new MongoApprovalStore(mongoApprovalRepository); 35 | } 36 | 37 | @Test 38 | public void shouldAddApprovals() { 39 | //Given 40 | final List approvals = list(ofApproval()).next(); 41 | 42 | //And 43 | given(mongoApprovalRepository.updateOrCreate(anyCollection())).willReturn(true); 44 | 45 | //When 46 | final boolean result = mongoApprovalStore.addApprovals(approvals); 47 | 48 | //Then 49 | assertThat(result).isTrue(); 50 | } 51 | 52 | @Test 53 | public void shouldReturnFalseWhenSomeApprovalsFailedToUpdateOrInsert() { 54 | //Given 55 | final List approvals = list(ofApproval()).next(); 56 | 57 | //And 58 | given(mongoApprovalRepository.updateOrCreate(anyCollection())).willReturn(false); 59 | 60 | //When 61 | final boolean result = mongoApprovalStore.addApprovals(approvals); 62 | 63 | //Then 64 | assertThat(result).isFalse(); 65 | } 66 | 67 | @Test 68 | public void shouldRevokeApprovalsByRemoveWhenHandleRevocationsAsExpiryIsFalse() { 69 | //Given 70 | final List approvals = list(ofApproval()).next(); 71 | 72 | //And 73 | mongoApprovalStore.setHandleRevocationsAsExpiry(false); 74 | 75 | //And 76 | given(mongoApprovalRepository.deleteByUserIdAndClientIdAndScope(any(MongoApproval.class))).willReturn(true); 77 | 78 | //When 79 | final boolean result = mongoApprovalStore.revokeApprovals(approvals); 80 | 81 | //Then 82 | assertThat(result).isTrue(); 83 | verify(mongoApprovalRepository, never()).updateExpiresAt(any(LocalDateTime.class), any(MongoApproval.class)); 84 | } 85 | 86 | @Test 87 | public void shouldReturnFalseWhenHandleRevocationsAsExpiryIsFalseAndThereIsNothingToDelete() { 88 | //Given 89 | final List approvals = list(ofApproval()).next(); 90 | 91 | //And 92 | mongoApprovalStore.setHandleRevocationsAsExpiry(false); 93 | 94 | //And 95 | given(mongoApprovalRepository.deleteByUserIdAndClientIdAndScope(any(MongoApproval.class))).willReturn(false); 96 | 97 | //When 98 | final boolean result = mongoApprovalStore.revokeApprovals(approvals); 99 | 100 | //Then 101 | assertThat(result).isFalse(); 102 | verify(mongoApprovalRepository, never()).updateExpiresAt(any(LocalDateTime.class), any(MongoApproval.class)); 103 | } 104 | 105 | @Test 106 | public void shouldRevokeApprovalsByUpdateWhenHandleRevocationsAsExpiryIsTrue() { 107 | //Given 108 | final List approvals = list(ofApproval()).next(); 109 | 110 | //And 111 | mongoApprovalStore.setHandleRevocationsAsExpiry(true); 112 | 113 | //And 114 | given(mongoApprovalRepository.updateExpiresAt(any(LocalDateTime.class), any(MongoApproval.class))).willReturn(true); 115 | 116 | //When 117 | final boolean result = mongoApprovalStore.revokeApprovals(approvals); 118 | 119 | //Then 120 | assertThat(result).isTrue(); 121 | verify(mongoApprovalRepository, never()).deleteByUserIdAndClientIdAndScope(any(MongoApproval.class)); 122 | } 123 | 124 | @Test 125 | public void shouldReturnFalseWhenHandleRevocationsAsExpiryIsTrueAndThereIsNothingToDelete() { 126 | //Given 127 | final List approvals = list(ofApproval()).next(); 128 | 129 | //And 130 | mongoApprovalStore.setHandleRevocationsAsExpiry(true); 131 | 132 | //And 133 | given(mongoApprovalRepository.updateExpiresAt(any(LocalDateTime.class), any(MongoApproval.class))).willReturn(false); 134 | 135 | //When 136 | final boolean result = mongoApprovalStore.revokeApprovals(approvals); 137 | 138 | //Then 139 | assertThat(result).isFalse(); 140 | verify(mongoApprovalRepository, never()).deleteByUserIdAndClientIdAndScope(any(MongoApproval.class)); 141 | } 142 | 143 | @Test 144 | public void shouldGetApprovals() { 145 | //Given 146 | final String userId = string().next(); 147 | final String clientId = string().next(); 148 | 149 | //And 150 | final List expectedMongoApprovals = list(ofMongoApproval()).next(); 151 | given(mongoApprovalRepository.findByUserIdAndClientId(userId, clientId)).willReturn(expectedMongoApprovals); 152 | 153 | //When 154 | final Collection approvals = mongoApprovalStore.getApprovals(userId, clientId); 155 | 156 | //Then 157 | assertThat(approvals).hasSameSizeAs(expectedMongoApprovals); 158 | } 159 | 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/MongoClientDetailsServiceIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.security.oauth2.provider.ClientDetails; 9 | import org.springframework.test.annotation.DirtiesContext; 10 | import org.springframework.test.context.ActiveProfiles; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | import uk.co.caeldev.springsecuritymongo.builders.MongoClientDetailsBuilder; 13 | import uk.co.caeldev.springsecuritymongo.config.ApplicationConfiguration; 14 | import uk.co.caeldev.springsecuritymongo.domain.MongoClientDetails; 15 | import uk.co.caeldev.springsecuritymongo.repositories.MongoClientDetailsRepository; 16 | 17 | import java.util.List; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { ApplicationConfiguration.class }) 23 | @ActiveProfiles("test") 24 | @DirtiesContext 25 | public class MongoClientDetailsServiceIntegrationTest { 26 | 27 | @Autowired 28 | private MongoClientDetailsService mongoClientDetailsService; 29 | 30 | @Autowired 31 | private MongoClientDetailsRepository mongoClientDetailsRepository; 32 | 33 | @Test 34 | public void shouldPersistClientDetailsSuccessfully() { 35 | //Given 36 | final MongoClientDetails clientDetails = MongoClientDetailsBuilder.mongoClientDetailsBuilder().build(); 37 | 38 | //When 39 | mongoClientDetailsService.addClientDetails(clientDetails); 40 | 41 | //Then 42 | final MongoClientDetails expectedClientDetails = mongoClientDetailsRepository.findByClientId(clientDetails.getClientId()); 43 | assertThat(expectedClientDetails).isNotNull(); 44 | assertThat(expectedClientDetails).isEqualTo(clientDetails); 45 | } 46 | 47 | @Test 48 | public void shouldLoadClientDetailsByIdSuccessfully() { 49 | //Given 50 | final MongoClientDetails clientDetails = MongoClientDetailsBuilder.mongoClientDetailsBuilder().build(); 51 | 52 | //And 53 | mongoClientDetailsService.addClientDetails(clientDetails); 54 | 55 | //When 56 | final ClientDetails expectedClientDetails = mongoClientDetailsService.loadClientByClientId(clientDetails.getClientId()); 57 | 58 | //Then 59 | assertThat(expectedClientDetails).isNotNull(); 60 | assertThat(expectedClientDetails).isEqualTo(clientDetails); 61 | } 62 | 63 | @Test 64 | public void shouldGetListOfClientDetailsByIdSuccessfully() { 65 | //Given 66 | final MongoClientDetails clientDetails = MongoClientDetailsBuilder.mongoClientDetailsBuilder().build(); 67 | 68 | //And 69 | mongoClientDetailsService.addClientDetails(clientDetails); 70 | 71 | //When 72 | final List expectedClientDetails = mongoClientDetailsService.listClientDetails(); 73 | 74 | //Then 75 | assertThat(expectedClientDetails).contains(clientDetails); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/MongoClientDetailsServiceTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.Mock; 7 | import org.mockito.junit.MockitoJUnitRunner; 8 | import org.springframework.security.crypto.password.PasswordEncoder; 9 | import org.springframework.security.oauth2.provider.ClientDetails; 10 | import org.springframework.security.oauth2.provider.NoSuchClientException; 11 | import uk.co.caeldev.springsecuritymongo.builders.ClientDetailsBuilder; 12 | import uk.co.caeldev.springsecuritymongo.builders.MongoClientDetailsBuilder; 13 | import uk.co.caeldev.springsecuritymongo.domain.MongoClientDetails; 14 | import uk.co.caeldev.springsecuritymongo.repositories.MongoClientDetailsRepository; 15 | 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | import static org.mockito.ArgumentMatchers.any; 18 | import static org.mockito.BDDMockito.given; 19 | import static org.mockito.Mockito.verify; 20 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.string; 21 | 22 | @RunWith(MockitoJUnitRunner.class) 23 | public class MongoClientDetailsServiceTest { 24 | 25 | @Mock 26 | private MongoClientDetailsRepository mongoClientDetailsRepository; 27 | 28 | @Mock 29 | private PasswordEncoder passwordEncoder; 30 | 31 | private MongoClientDetailsService mongoClientDetailsService; 32 | 33 | @Before 34 | public void setup() { 35 | mongoClientDetailsService = new MongoClientDetailsService(mongoClientDetailsRepository, passwordEncoder); 36 | } 37 | 38 | @Test 39 | public void shouldAddClientDetails() { 40 | //Given 41 | final ClientDetails clientDetails = ClientDetailsBuilder.clientDetailsBuilder().build(); 42 | 43 | //When 44 | mongoClientDetailsService.addClientDetails(clientDetails); 45 | 46 | //Then 47 | verify(mongoClientDetailsRepository).save(any(MongoClientDetails.class)); 48 | verify(passwordEncoder).encode(clientDetails.getClientSecret()); 49 | } 50 | 51 | @Test 52 | public void shouldRemoveClientDetailsWithValidClientId() { 53 | //Given 54 | final String clientId = string().next(); 55 | 56 | //And 57 | given(mongoClientDetailsRepository.deleteByClientId(clientId)).willReturn(true); 58 | 59 | //When 60 | mongoClientDetailsService.removeClientDetails(clientId); 61 | } 62 | 63 | @Test(expected = NoSuchClientException.class) 64 | public void shouldThrowsExceptionWhenTryToRemoveClientDetailsWithInvalidClientId() { 65 | //Given 66 | final String clientId = string().next(); 67 | 68 | //And 69 | given(mongoClientDetailsRepository.deleteByClientId(clientId)).willReturn(false); 70 | 71 | //When 72 | mongoClientDetailsService.removeClientDetails(clientId); 73 | } 74 | 75 | @Test 76 | public void shouldUpdateClientDetails() throws NoSuchClientException { 77 | //Given 78 | final ClientDetails clientDetails = ClientDetailsBuilder.clientDetailsBuilder().build(); 79 | 80 | //And 81 | given(mongoClientDetailsRepository.update(any(MongoClientDetails.class))).willReturn(true); 82 | 83 | //When 84 | mongoClientDetailsService.updateClientDetails(clientDetails); 85 | } 86 | 87 | @Test(expected = NoSuchClientException.class) 88 | public void shouldNotUpdateClientDetailsWhenClientIdIsNotValid() throws NoSuchClientException { 89 | //Given 90 | final ClientDetails clientDetails = ClientDetailsBuilder.clientDetailsBuilder().build(); 91 | 92 | //And 93 | given(mongoClientDetailsRepository.update(any(MongoClientDetails.class))).willReturn(false); 94 | 95 | //When 96 | mongoClientDetailsService.updateClientDetails(clientDetails); 97 | } 98 | 99 | @Test 100 | public void shouldUpdateClientSecret() throws NoSuchClientException { 101 | //Given 102 | final String clientId = string().next(); 103 | final String secret = string().next(); 104 | 105 | //And 106 | final String expectedNewSecret = string().next(); 107 | given(passwordEncoder.encode(secret)).willReturn(expectedNewSecret); 108 | 109 | //And 110 | given(mongoClientDetailsRepository.updateClientSecret(clientId, expectedNewSecret)).willReturn(true); 111 | 112 | //When 113 | mongoClientDetailsService.updateClientSecret(clientId, secret); 114 | } 115 | 116 | @Test(expected = NoSuchClientException.class) 117 | public void shouldNotUpdateClientSecretWhenClientIdIsInvalid() throws NoSuchClientException { 118 | //Given 119 | final String clientId = string().next(); 120 | final String secret = string().next(); 121 | 122 | //And 123 | final String expectedNewSecret = string().next(); 124 | given(passwordEncoder.encode(secret)).willReturn(expectedNewSecret); 125 | 126 | //And 127 | given(mongoClientDetailsRepository.updateClientSecret(clientId, expectedNewSecret)).willReturn(false); 128 | 129 | //When 130 | mongoClientDetailsService.updateClientSecret(clientId, secret); 131 | } 132 | 133 | @Test 134 | public void shouldLoadClientByClientId() throws NoSuchClientException { 135 | //Given 136 | final String clientId = string().next(); 137 | 138 | final MongoClientDetails expectedClientDetails = MongoClientDetailsBuilder.mongoClientDetailsBuilder().build(); 139 | given(mongoClientDetailsRepository.findByClientId(clientId)).willReturn(expectedClientDetails); 140 | 141 | //When 142 | final ClientDetails clientDetails = mongoClientDetailsService.loadClientByClientId(clientId); 143 | 144 | //Then 145 | assertThat(clientDetails.getClientId()).isEqualTo(expectedClientDetails.getClientId()); 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/MongoClientTokenServicesTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.Mock; 7 | import org.mockito.junit.MockitoJUnitRunner; 8 | import org.springframework.security.authentication.TestingAuthenticationToken; 9 | import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; 10 | import org.springframework.security.oauth2.client.token.ClientKeyGenerator; 11 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 12 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2ClientToken; 13 | import uk.co.caeldev.springsecuritymongo.repositories.MongoOAuth2ClientTokenRepository; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | import static org.mockito.ArgumentMatchers.any; 17 | import static org.mockito.BDDMockito.given; 18 | import static org.mockito.Mockito.*; 19 | import static uk.co.caeldev.springsecuritymongo.builders.MongoOAuth2ClientTokenBuilder.mongoOAuth2ClientTokenBuilder; 20 | import static uk.co.caeldev.springsecuritymongo.builders.OAuth2AccessTokenBuilder.oAuth2AccessTokenBuilder; 21 | import static uk.co.caeldev.springsecuritymongo.builders.OAuth2ProtectedResourceDetailsBuilder.oAuth2ProtectedResourceDetailsBuilder; 22 | import static uk.co.caeldev.springsecuritymongo.builders.UserBuilder.userBuilder; 23 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.string; 24 | 25 | @RunWith(MockitoJUnitRunner.class) 26 | public class MongoClientTokenServicesTest { 27 | 28 | @Mock 29 | private MongoOAuth2ClientTokenRepository mongoOAuth2ClientTokenRepository; 30 | 31 | @Mock 32 | private ClientKeyGenerator keyGenerator; 33 | 34 | private MongoClientTokenServices mongoClientTokenServices; 35 | 36 | @Before 37 | public void setup() { 38 | mongoClientTokenServices = new MongoClientTokenServices(mongoOAuth2ClientTokenRepository, keyGenerator); 39 | } 40 | 41 | @Test 42 | public void shouldSaveAccessToken() { 43 | //Given 44 | final OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails = oAuth2ProtectedResourceDetailsBuilder().build(); 45 | final TestingAuthenticationToken authentication = new TestingAuthenticationToken(userBuilder().build(), string().next()); 46 | final OAuth2AccessToken oAuth2AccessToken = oAuth2AccessTokenBuilder().build(); 47 | 48 | //And 49 | final String authenticationId = string().next(); 50 | given(keyGenerator.extractKey(oAuth2ProtectedResourceDetails, authentication)).willReturn(authenticationId); 51 | 52 | //When 53 | mongoClientTokenServices.saveAccessToken(oAuth2ProtectedResourceDetails, authentication, oAuth2AccessToken); 54 | 55 | //Then 56 | verify(keyGenerator, atLeastOnce()).extractKey(oAuth2ProtectedResourceDetails, authentication); 57 | verify(mongoOAuth2ClientTokenRepository).save(any(MongoOAuth2ClientToken.class)); 58 | verify(mongoOAuth2ClientTokenRepository).deleteByAuthenticationId(authenticationId); 59 | } 60 | 61 | @Test 62 | public void shouldRemoveAccessToken() { 63 | //Given 64 | final OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails = oAuth2ProtectedResourceDetailsBuilder().build(); 65 | final TestingAuthenticationToken authentication = new TestingAuthenticationToken(userBuilder().build(), string().next()); 66 | 67 | //And 68 | final String value = string().next(); 69 | when(keyGenerator.extractKey(oAuth2ProtectedResourceDetails, authentication)).thenReturn(value); 70 | //When 71 | mongoClientTokenServices.removeAccessToken(oAuth2ProtectedResourceDetails, authentication); 72 | 73 | //Then 74 | verify(mongoOAuth2ClientTokenRepository).deleteByAuthenticationId(value); 75 | } 76 | 77 | @Test 78 | public void shouldGetAccessToken() { 79 | //Given 80 | final OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails = oAuth2ProtectedResourceDetailsBuilder().build(); 81 | final TestingAuthenticationToken authentication = new TestingAuthenticationToken(userBuilder().build(), string().next()); 82 | 83 | //And 84 | final String authenticationId = string().next(); 85 | given(keyGenerator.extractKey(oAuth2ProtectedResourceDetails, authentication)).willReturn(authenticationId); 86 | 87 | //And 88 | final OAuth2AccessToken expectedToken = oAuth2AccessTokenBuilder().build(); 89 | given(mongoOAuth2ClientTokenRepository.findByAuthenticationId(authenticationId)).willReturn(mongoOAuth2ClientTokenBuilder().token(expectedToken).build()); 90 | 91 | //When 92 | final OAuth2AccessToken accessToken = mongoClientTokenServices.getAccessToken(oAuth2ProtectedResourceDetails, authentication); 93 | 94 | //Then 95 | assertThat(accessToken).isEqualTo(expectedToken); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/MongoTokenStoreTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.mockito.ArgumentCaptor; 6 | import org.mockito.InjectMocks; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.MockitoJUnitRunner; 9 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 10 | import org.springframework.security.oauth2.common.OAuth2RefreshToken; 11 | import org.springframework.security.oauth2.common.util.SerializationUtils; 12 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 13 | import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator; 14 | import uk.co.caeldev.springsecuritymongo.builders.*; 15 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2AccessToken; 16 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2RefreshToken; 17 | import uk.co.caeldev.springsecuritymongo.repositories.MongoOAuth2AccessTokenRepository; 18 | import uk.co.caeldev.springsecuritymongo.repositories.MongoOAuth2RefreshTokenRepository; 19 | 20 | import java.util.Collection; 21 | import java.util.List; 22 | 23 | import static org.assertj.core.api.Assertions.assertThat; 24 | import static org.mockito.BDDMockito.given; 25 | import static org.mockito.Mockito.*; 26 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.*; 27 | 28 | @RunWith(MockitoJUnitRunner.class) 29 | public class MongoTokenStoreTest { 30 | 31 | @Mock 32 | private MongoOAuth2AccessTokenRepository mongoOAuth2AccessTokenRepository; 33 | 34 | @Mock 35 | private MongoOAuth2RefreshTokenRepository mongoOAuth2RefreshTokenRepository; 36 | 37 | @Mock 38 | private AuthenticationKeyGenerator authenticationKeyGenerator; 39 | 40 | @InjectMocks 41 | private MongoTokenStore mongoTokenStore; 42 | 43 | @Test 44 | public void shouldStoreAccessToken() { 45 | //Given 46 | final OAuth2AccessToken auth2AccessToken = OAuth2AccessTokenBuilder.oAuth2AccessTokenBuilder().build(); 47 | final byte[] token = SerializationUtils.serialize(auth2AccessToken); 48 | 49 | //And 50 | final OAuth2Authentication oAuth2Authentication = OAuth2AuthenticationBuilder.oAuth2AuthenticationBuilder().build(); 51 | 52 | //And 53 | given(mongoOAuth2AccessTokenRepository.findByTokenId(any(String.class))) 54 | .willReturn(MongoOAuth2AccessTokenBuilder.mongoOAuth2AccessTokenBuilder().token(token).build()); 55 | 56 | //When 57 | mongoTokenStore.storeAccessToken(auth2AccessToken, oAuth2Authentication); 58 | 59 | //Then 60 | verify(mongoOAuth2AccessTokenRepository).deleteByTokenId(any(String.class)); 61 | verify(mongoOAuth2AccessTokenRepository).save(any(MongoOAuth2AccessToken.class)); 62 | } 63 | 64 | @Test 65 | public void shouldReadAccessToken() { 66 | //Given 67 | final String tokenValue = string().next(); 68 | 69 | //And 70 | final OAuth2AccessToken auth2AccessToken = OAuth2AccessTokenBuilder.oAuth2AccessTokenBuilder().token(tokenValue).build(); 71 | final byte[] token = SerializationUtils.serialize(auth2AccessToken); 72 | 73 | //And 74 | given(mongoOAuth2AccessTokenRepository.findByTokenId(any(String.class))) 75 | .willReturn(MongoOAuth2AccessTokenBuilder.mongoOAuth2AccessTokenBuilder() 76 | .token(token) 77 | .build()); 78 | 79 | //When 80 | final OAuth2AccessToken oAuth2AccessToken = mongoTokenStore.readAccessToken(tokenValue); 81 | 82 | //Then 83 | assertThat(oAuth2AccessToken.getValue()).isEqualTo(tokenValue); 84 | } 85 | 86 | @Test 87 | public void shouldReturnNullWhenNoReadAccessToken() { 88 | //Given 89 | final String tokenValue = string().next(); 90 | 91 | //And 92 | given(mongoOAuth2AccessTokenRepository.findByTokenId(any(String.class))) 93 | .willReturn(null); 94 | 95 | //When 96 | final OAuth2AccessToken oAuth2AccessToken = mongoTokenStore.readAccessToken(tokenValue); 97 | 98 | //Then 99 | assertThat(oAuth2AccessToken).isNull(); 100 | } 101 | 102 | @Test 103 | public void shouldRemoveAccessToken() { 104 | //Given 105 | final OAuth2AccessToken oAuth2AccessToken = OAuth2AccessTokenBuilder.oAuth2AccessTokenBuilder().build(); 106 | 107 | //When 108 | mongoTokenStore.removeAccessToken(oAuth2AccessToken); 109 | 110 | //Then 111 | verify(mongoOAuth2AccessTokenRepository).deleteByTokenId(any(String.class)); 112 | } 113 | 114 | @Test 115 | public void shouldStoreRefreshToken() { 116 | //Given 117 | final OAuth2RefreshToken oAuth2RefreshToken = OAuth2RefreshTokenBuilder.oAuth2RefreshToken().build(); 118 | 119 | //And 120 | final OAuth2Authentication oAuth2Authentication = OAuth2AuthenticationBuilder.oAuth2AuthenticationBuilder().build(); 121 | 122 | //And 123 | final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(MongoOAuth2RefreshToken.class); 124 | 125 | //When 126 | mongoTokenStore.storeRefreshToken(oAuth2RefreshToken, oAuth2Authentication); 127 | 128 | //Then 129 | verify(mongoOAuth2RefreshTokenRepository).save(argumentCaptor.capture()); 130 | final MongoOAuth2RefreshToken refreshToken = argumentCaptor.getValue(); 131 | final byte[] expectedResult = SerializationUtils.serialize(oAuth2RefreshToken); 132 | assertThat(refreshToken.getToken()).isEqualTo(expectedResult); 133 | 134 | } 135 | 136 | @Test 137 | public void shouldReadRefreshToken() { 138 | //Given 139 | final String tokenValue = string().next(); 140 | final OAuth2RefreshToken oAuth2RefreshToken = OAuth2RefreshTokenBuilder.oAuth2RefreshToken().build(); 141 | final byte[] oAuth2RefreshTokenSer = SerializationUtils.serialize(oAuth2RefreshToken); 142 | 143 | //And 144 | given(mongoOAuth2RefreshTokenRepository.findByTokenId(any(String.class))) 145 | .willReturn(MongoOAuth2RefreshTokenBuilder.mongoOAuth2RefreshTokenBuilder().token(oAuth2RefreshTokenSer).build()); 146 | 147 | //When 148 | final OAuth2RefreshToken result = mongoTokenStore.readRefreshToken(tokenValue); 149 | 150 | //Then 151 | assertThat(result.getValue()).isEqualTo(oAuth2RefreshToken.getValue()); 152 | } 153 | 154 | @Test 155 | public void shouldReadNullWhenNoRefreshToken() { 156 | //Given 157 | final String tokenValue = string().next(); 158 | 159 | //And 160 | given(mongoOAuth2RefreshTokenRepository.findByTokenId(any(String.class))) 161 | .willReturn(null); 162 | 163 | //When 164 | final OAuth2RefreshToken result = mongoTokenStore.readRefreshToken(tokenValue); 165 | 166 | //Then 167 | assertThat(result).isNull(); 168 | } 169 | 170 | @Test 171 | public void shouldReadAuthenticationForRefreshToken() { 172 | //Given 173 | final OAuth2RefreshToken oAuth2RefreshToken = OAuth2RefreshTokenBuilder.oAuth2RefreshToken().build(); 174 | 175 | //And 176 | final OAuth2Authentication authentication = OAuth2AuthenticationBuilder.oAuth2AuthenticationBuilder().build(); 177 | final byte[] authenticationSer = SerializationUtils.serialize(authentication); 178 | 179 | //And 180 | given(mongoOAuth2RefreshTokenRepository.findByTokenId(any(String.class))) 181 | .willReturn(MongoOAuth2RefreshTokenBuilder.mongoOAuth2RefreshTokenBuilder() 182 | .authentication(authenticationSer) 183 | .build()); 184 | //When 185 | final OAuth2Authentication oAuth2Authentication = mongoTokenStore.readAuthenticationForRefreshToken(oAuth2RefreshToken); 186 | 187 | //Then 188 | assertThat(oAuth2Authentication.getPrincipal()).isEqualTo(authentication.getPrincipal()); 189 | assertThat(oAuth2Authentication.getCredentials()).isEqualTo(authentication.getCredentials()); 190 | } 191 | 192 | @Test 193 | public void shouldReadNullWhenAuthenticationForNoRefreshToken() { 194 | //Given 195 | final OAuth2RefreshToken oAuth2RefreshToken = OAuth2RefreshTokenBuilder.oAuth2RefreshToken().build(); 196 | 197 | //And 198 | given(mongoOAuth2RefreshTokenRepository.findByTokenId(any(String.class))) 199 | .willReturn(null); 200 | //When 201 | final OAuth2Authentication oAuth2Authentication = mongoTokenStore.readAuthenticationForRefreshToken(oAuth2RefreshToken); 202 | 203 | //Then 204 | assertThat(oAuth2Authentication).isNull(); 205 | } 206 | 207 | @Test 208 | public void shouldRemoveRefreshToken() { 209 | //Given 210 | final OAuth2RefreshToken oAuth2RefreshToken = OAuth2RefreshTokenBuilder.oAuth2RefreshToken().build(); 211 | 212 | //When 213 | mongoTokenStore.removeRefreshToken(oAuth2RefreshToken); 214 | 215 | //Then 216 | verify(mongoOAuth2RefreshTokenRepository).deleteByTokenId(any(String.class)); 217 | } 218 | 219 | @Test 220 | public void shouldRemoveAccessTokenUsingRefreshToken() { 221 | //Given 222 | final OAuth2RefreshToken oAuth2RefreshToken = OAuth2RefreshTokenBuilder.oAuth2RefreshToken().build(); 223 | 224 | //When 225 | mongoTokenStore.removeAccessTokenUsingRefreshToken(oAuth2RefreshToken); 226 | 227 | //Then 228 | verify(mongoOAuth2AccessTokenRepository).deleteByRefreshTokenId(any(String.class)); 229 | } 230 | 231 | @Test 232 | public void shouldGetAccessToken() { 233 | //Given 234 | final OAuth2Authentication oAuth2Authentication = OAuth2AuthenticationBuilder.oAuth2AuthenticationBuilder().build(); 235 | 236 | //And 237 | final String value = string().next(); 238 | doReturn(value).doReturn(value).when(authenticationKeyGenerator).extractKey(any()); 239 | 240 | //And 241 | final OAuth2AccessToken oAuth2AccessToken = OAuth2AccessTokenBuilder.oAuth2AccessTokenBuilder().build(); 242 | 243 | final byte[] oAuth2AccessTokenSer = SerializationUtils.serialize(oAuth2AccessToken); 244 | given(mongoOAuth2AccessTokenRepository.findByAuthenticationId(value)) 245 | .willReturn(MongoOAuth2AccessTokenBuilder.mongoOAuth2AccessTokenBuilder() 246 | .token(oAuth2AccessTokenSer) 247 | .build()); 248 | 249 | //And 250 | given(mongoOAuth2AccessTokenRepository.findByTokenId(any())) 251 | .willReturn(MongoOAuth2AccessTokenBuilder.mongoOAuth2AccessTokenBuilder().build()); 252 | 253 | //When 254 | mongoTokenStore.getAccessToken(oAuth2Authentication); 255 | 256 | //Then 257 | verify(mongoOAuth2AccessTokenRepository, never()).deleteByTokenId(any(String.class)); 258 | verify(mongoOAuth2AccessTokenRepository, never()).save(any(MongoOAuth2AccessToken.class)); 259 | } 260 | 261 | @Test 262 | public void shouldReturnNullWhenNoAccessToken() { 263 | //Given 264 | final OAuth2Authentication oAuth2Authentication = OAuth2AuthenticationBuilder.oAuth2AuthenticationBuilder().build(); 265 | 266 | //And 267 | final String value = string().next(); 268 | given(authenticationKeyGenerator.extractKey(oAuth2Authentication)).willReturn(value); 269 | 270 | //And 271 | given(mongoOAuth2AccessTokenRepository.findByAuthenticationId(value)) 272 | .willReturn(null); 273 | 274 | //When 275 | mongoTokenStore.getAccessToken(oAuth2Authentication); 276 | 277 | //Then 278 | verify(mongoOAuth2AccessTokenRepository, never()).deleteByTokenId(any(String.class)); 279 | verify(mongoOAuth2AccessTokenRepository, never()).save(any(MongoOAuth2AccessToken.class)); 280 | verify(mongoOAuth2AccessTokenRepository, never()).findByTokenId(anyString()); 281 | } 282 | 283 | @Test 284 | public void shouldGetAccessTokenAndRemoveOldTokenAndPersistNewOne() { 285 | //Given 286 | final OAuth2Authentication oAuth2Authentication = OAuth2AuthenticationBuilder.oAuth2AuthenticationBuilder().build(); 287 | 288 | //And 289 | final String value = string().next(); 290 | given(authenticationKeyGenerator.extractKey(oAuth2Authentication)).willReturn(value); 291 | 292 | //And 293 | given(mongoOAuth2AccessTokenRepository.findByAuthenticationId(value)) 294 | .willReturn(MongoOAuth2AccessTokenBuilder.mongoOAuth2AccessTokenBuilder() 295 | .build()); 296 | 297 | //And 298 | given(mongoOAuth2AccessTokenRepository.findByTokenId(anyString())).willReturn(MongoOAuth2AccessTokenBuilder.mongoOAuth2AccessTokenBuilder().build()); 299 | 300 | //When 301 | mongoTokenStore.getAccessToken(oAuth2Authentication); 302 | 303 | //Then 304 | verify(mongoOAuth2AccessTokenRepository, atLeastOnce()).deleteByTokenId(any(String.class)); 305 | verify(mongoOAuth2AccessTokenRepository).save(any(MongoOAuth2AccessToken.class)); 306 | } 307 | 308 | @Test 309 | public void shouldFindTokensByClientIdAndUserName() { 310 | //Given 311 | final String username = string().next(); 312 | final String clientId = string().next(); 313 | 314 | //And 315 | final List expectedTokens = list(ofMongoOAuth2AccessToken()).next(); 316 | given(mongoOAuth2AccessTokenRepository.findByUsernameAndClientId(username, clientId)).willReturn(expectedTokens); 317 | 318 | //When 319 | final Collection tokens = mongoTokenStore.findTokensByClientIdAndUserName(clientId, username); 320 | 321 | //Then 322 | assertThat(tokens).hasSize(expectedTokens.size()); 323 | } 324 | 325 | @Test 326 | public void shouldFindTokensByClientId() { 327 | //Given 328 | final String clientId = string().next(); 329 | 330 | //And 331 | final List expectedTokens = list(ofMongoOAuth2AccessToken()).next(); 332 | given(mongoOAuth2AccessTokenRepository.findByClientId(clientId)).willReturn(expectedTokens); 333 | 334 | //When 335 | final Collection tokens = mongoTokenStore.findTokensByClientId(clientId); 336 | 337 | //Then 338 | assertThat(tokens).hasSize(expectedTokens.size()); 339 | } 340 | 341 | } 342 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/MongoUserDetailsManagerTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.Mock; 7 | import org.mockito.junit.MockitoJUnitRunner; 8 | import org.springframework.security.authentication.AuthenticationManager; 9 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 10 | import org.springframework.security.core.Authentication; 11 | import org.springframework.security.core.userdetails.UserDetails; 12 | import uk.co.caeldev.springsecuritymongo.builders.UserBuilder; 13 | import uk.co.caeldev.springsecuritymongo.commons.SecurityRDG; 14 | import uk.co.caeldev.springsecuritymongo.domain.User; 15 | import uk.co.caeldev.springsecuritymongo.repositories.UserRepository; 16 | import uk.co.caeldev.springsecuritymongo.services.SecurityContextService; 17 | 18 | import java.util.Optional; 19 | 20 | import static org.assertj.core.api.Assertions.assertThat; 21 | import static org.mockito.ArgumentMatchers.any; 22 | import static org.mockito.BDDMockito.given; 23 | import static org.mockito.Mockito.verify; 24 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.string; 25 | 26 | @RunWith(MockitoJUnitRunner.class) 27 | public class MongoUserDetailsManagerTest { 28 | 29 | @Mock 30 | private UserRepository userRepository; 31 | 32 | @Mock 33 | private AuthenticationManager authenticationManager; 34 | 35 | @Mock 36 | private SecurityContextService securityContextService; 37 | 38 | private MongoUserDetailsManager mongoUserDetailsManager; 39 | 40 | @Before 41 | public void setup() { 42 | mongoUserDetailsManager = new MongoUserDetailsManager(userRepository, securityContextService, authenticationManager); 43 | } 44 | 45 | @Test 46 | public void shouldCreateUser() { 47 | // Given 48 | final User user = UserBuilder.userBuilder().build(); 49 | 50 | // When 51 | mongoUserDetailsManager.createUser(user); 52 | 53 | // Then 54 | verify(userRepository).save(user); 55 | } 56 | 57 | @Test(expected = IllegalArgumentException.class) 58 | public void shouldNotCreateUserWhenUsernameIsEmpty() { 59 | // Given 60 | final User user = UserBuilder.userBuilder().username("").build(); 61 | 62 | // When 63 | mongoUserDetailsManager.createUser(user); 64 | } 65 | 66 | @Test(expected = IllegalArgumentException.class) 67 | public void shouldNotCreateUserWhenUsernameIsValidAndNoAuthorities() { 68 | // Given 69 | final User user = UserBuilder.userBuilder().authorities(null).build(); 70 | 71 | // When 72 | mongoUserDetailsManager.createUser(user); 73 | } 74 | 75 | @Test(expected = IllegalArgumentException.class) 76 | public void shouldNotCreateUserWhenUsernameIsValidAndAuthoritiesNotValid() { 77 | // Given 78 | final User user = UserBuilder.userBuilder().authorities(SecurityRDG.set(SecurityRDG.ofInvalidAuthority()).next()).build(); 79 | 80 | // When 81 | mongoUserDetailsManager.createUser(user); 82 | } 83 | 84 | @Test 85 | public void shouldDeleteUser() { 86 | // Given 87 | final String username = string().next(); 88 | 89 | // When 90 | mongoUserDetailsManager.deleteUser(username); 91 | 92 | //Then 93 | verify(userRepository).deleteByUsername(username); 94 | } 95 | 96 | @Test 97 | public void shouldUpdateUser() { 98 | // Given 99 | final User user = UserBuilder.userBuilder().build(); 100 | 101 | // When 102 | mongoUserDetailsManager.updateUser(user); 103 | 104 | // Then 105 | verify(userRepository).save(user); 106 | } 107 | 108 | @Test(expected = IllegalArgumentException.class) 109 | public void shouldNotUpdateUserWhenUsernameIsInvalid() { 110 | // Given 111 | final User user = UserBuilder.userBuilder().username("").build(); 112 | 113 | // When 114 | mongoUserDetailsManager.updateUser(user); 115 | } 116 | 117 | @Test(expected = IllegalArgumentException.class) 118 | public void shouldNotUpdateUserWhenUsernameIsValidAndNoAuthorities() { 119 | // Given 120 | final User user = UserBuilder.userBuilder().authorities(null).build(); 121 | 122 | // When 123 | mongoUserDetailsManager.updateUser(user); 124 | } 125 | 126 | @Test(expected = IllegalArgumentException.class) 127 | public void shouldNotUpdateUserWhenUsernameIsValidAndAuthoritiesNotValid() { 128 | // Given 129 | final User user = UserBuilder.userBuilder().authorities(SecurityRDG.set(SecurityRDG.ofInvalidAuthority()).next()).build(); 130 | 131 | // When 132 | mongoUserDetailsManager.updateUser(user); 133 | } 134 | 135 | @Test 136 | public void shouldReturnTrueWhenUserExists() { 137 | // Given 138 | final String username = string().next(); 139 | final User user = UserBuilder.userBuilder().username(username).build(); 140 | 141 | // And 142 | given(userRepository.findByUsername(username)).willReturn(Optional.of(user)); 143 | 144 | // When 145 | final boolean userExists = mongoUserDetailsManager.userExists(username); 146 | 147 | // Then 148 | assertThat(userExists).isTrue(); 149 | } 150 | 151 | @Test 152 | public void shouldReturnFalseWhenUserDoesNotExists() { 153 | // Given 154 | final String username = string().next(); 155 | 156 | // And 157 | given(userRepository.findByUsername(username)).willReturn(Optional.empty()); 158 | 159 | // When 160 | final boolean userExists = mongoUserDetailsManager.userExists(username); 161 | 162 | // Then 163 | assertThat(userExists).isFalse(); 164 | } 165 | 166 | @Test 167 | public void shouldLoadUserByUsernameWhenUserExists() { 168 | // Given 169 | final String username = string().next(); 170 | 171 | // And 172 | given(userRepository.findByUsername(username)).willReturn(Optional.of(UserBuilder.userBuilder().username(username).build())); 173 | 174 | // When 175 | final UserDetails user = mongoUserDetailsManager.loadUserByUsername(username); 176 | 177 | // Then 178 | assertThat(user).isNotNull(); 179 | assertThat(user.getUsername()).isEqualTo(username); 180 | } 181 | 182 | @Test 183 | public void shouldChangePasswordForExitingUser() { 184 | // Given 185 | final String username = string().next(); 186 | final String currentPassword = string().next(); 187 | final User user = UserBuilder.userBuilder().username(username).password(currentPassword).build(); 188 | 189 | // And 190 | final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, currentPassword); 191 | given(securityContextService.getAuthentication()).willReturn(authenticationToken); 192 | 193 | // And 194 | given(userRepository.findByUsername(username)).willReturn(Optional.of(user)); 195 | 196 | // When 197 | final String newPassword = string().next(); 198 | mongoUserDetailsManager.changePassword(currentPassword, newPassword); 199 | 200 | // Then 201 | verify(authenticationManager).authenticate(any(Authentication.class)); 202 | verify(securityContextService).setAuthentication(any(Authentication.class)); 203 | verify(userRepository).changePassword(currentPassword, newPassword, username); 204 | } 205 | 206 | } -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/ApprovalBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.oauth2.provider.approval.Approval; 4 | 5 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.*; 6 | 7 | public class ApprovalBuilder { 8 | 9 | private String userId = string().next(); 10 | private String clientId = string().next(); 11 | private String scope = string().next(); 12 | private Integer expiresIn = integer().next(); 13 | private Approval.ApprovalStatus status = value(Approval.ApprovalStatus.class).next(); 14 | 15 | private ApprovalBuilder() { 16 | } 17 | 18 | public static ApprovalBuilder approvalBuilder() { 19 | return new ApprovalBuilder(); 20 | } 21 | 22 | public Approval build() { 23 | return new Approval(userId, clientId, scope, expiresIn, status); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/ClientDetailsBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import com.google.common.base.Joiner; 4 | import org.springframework.security.oauth2.provider.ClientDetails; 5 | import org.springframework.security.oauth2.provider.client.BaseClientDetails; 6 | 7 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.list; 8 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.string; 9 | 10 | public class ClientDetailsBuilder { 11 | 12 | private String clientId = string().next(); 13 | private String resourceIds = Joiner.on(",").join(list(string()).next()); 14 | private String scopes = Joiner.on(",").join(list(string()).next()); 15 | private String grantTypes = Joiner.on(",").join(list(string()).next()); 16 | private String authorities = Joiner.on(",").join(list(string()).next()); 17 | 18 | private ClientDetailsBuilder() { 19 | } 20 | 21 | public static ClientDetailsBuilder clientDetailsBuilder() { 22 | return new ClientDetailsBuilder(); 23 | } 24 | 25 | public ClientDetails build() { 26 | return new BaseClientDetails(clientId, resourceIds, scopes, grantTypes, authorities); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/MongoApprovalBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.oauth2.provider.approval.Approval; 4 | import uk.co.caeldev.springsecuritymongo.domain.MongoApproval; 5 | 6 | import java.time.LocalDateTime; 7 | import java.util.UUID; 8 | 9 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.*; 10 | 11 | public class MongoApprovalBuilder { 12 | 13 | private String id = UUID.randomUUID().toString(); 14 | private String userId = string().next(); 15 | private String clientId = string().next(); 16 | private String scope = string().next(); 17 | private Approval.ApprovalStatus status = value(Approval.ApprovalStatus.class).next(); 18 | private LocalDateTime expiresAt = localDateTime().next(); 19 | private LocalDateTime lastUpdatedAt = localDateTime().next(); 20 | 21 | private MongoApprovalBuilder() { 22 | } 23 | 24 | public static MongoApprovalBuilder mongoApprovalBuilder() { 25 | return new MongoApprovalBuilder(); 26 | } 27 | 28 | public MongoApproval build() { 29 | return new MongoApproval(id, userId, clientId, scope, status, expiresAt, lastUpdatedAt); 30 | } 31 | 32 | public MongoApprovalBuilder clientId(String clientId) { 33 | this.clientId = clientId; 34 | return this; 35 | } 36 | 37 | public MongoApprovalBuilder userId(String userId) { 38 | this.userId = userId; 39 | return this; 40 | } 41 | 42 | public MongoApprovalBuilder scope(String scope) { 43 | this.scope = scope; 44 | return this; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/MongoClientDetailsBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import com.google.common.collect.Sets; 4 | import org.springframework.security.core.GrantedAuthority; 5 | import uk.co.caeldev.springsecuritymongo.domain.MongoClientDetails; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.*; 12 | 13 | public class MongoClientDetailsBuilder { 14 | 15 | private String clientId = ofEscapedString().next(); 16 | private String clientSecret = ofEscapedString().next(); 17 | private Set scope = set(ofEscapedString()).next(); 18 | private Set resourceIds = set(ofEscapedString()).next(); 19 | private Set authorizedGrantTypes = set(ofEscapedString()).next(); 20 | private Set registeredRedirectUris = set(ofEscapedString()).next(); 21 | private List authorities = list(ofGrantedAuthority()).next(); 22 | private Integer accessTokenValiditySeconds = integer().next(); 23 | private Integer refreshTokenValiditySeconds = integer().next(); 24 | private Map additionalInformation = map(ofEscapedString(), objectOf(ofEscapedString())).next(); 25 | 26 | private Set autoApproveScopes = Sets.newHashSet("true"); 27 | 28 | private MongoClientDetailsBuilder() { 29 | } 30 | 31 | public static MongoClientDetailsBuilder mongoClientDetailsBuilder() { 32 | return new MongoClientDetailsBuilder(); 33 | } 34 | 35 | public MongoClientDetails build() { 36 | return new MongoClientDetails(clientId, 37 | clientSecret, 38 | scope, 39 | resourceIds, 40 | authorizedGrantTypes, 41 | registeredRedirectUris, 42 | authorities, 43 | accessTokenValiditySeconds, 44 | refreshTokenValiditySeconds, 45 | additionalInformation, 46 | autoApproveScopes); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/MongoOAuth2AccessTokenBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.oauth2.common.util.SerializationUtils; 4 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2AccessToken; 5 | 6 | import static uk.co.caeldev.springsecuritymongo.builders.OAuth2AccessTokenBuilder.oAuth2AccessTokenBuilder; 7 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.string; 8 | 9 | public class MongoOAuth2AccessTokenBuilder { 10 | 11 | private String tokenId = string().next(); 12 | private byte[] token = SerializationUtils.serialize(oAuth2AccessTokenBuilder().build()); 13 | private String authenticationId = string().next(); 14 | private String username = string().next(); 15 | private String clientId = string().next(); 16 | private byte[] authentication = SerializationUtils.serialize(OAuth2AuthenticationBuilder.oAuth2AuthenticationBuilder().build()); 17 | private String refreshToken = string().next(); 18 | 19 | private MongoOAuth2AccessTokenBuilder() { 20 | } 21 | 22 | public static MongoOAuth2AccessTokenBuilder mongoOAuth2AccessTokenBuilder() { 23 | return new MongoOAuth2AccessTokenBuilder(); 24 | } 25 | 26 | 27 | public MongoOAuth2AccessToken build() { 28 | return new MongoOAuth2AccessToken(tokenId, token, authenticationId, username, clientId, authentication, refreshToken); 29 | } 30 | 31 | public MongoOAuth2AccessTokenBuilder token(final byte[] token) { 32 | this.token = token; 33 | return this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/MongoOAuth2ClientTokenBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 4 | import org.springframework.util.SerializationUtils; 5 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2ClientToken; 6 | 7 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.string; 8 | 9 | public class MongoOAuth2ClientTokenBuilder { 10 | 11 | private String id = string().next(); 12 | private String tokenId = string().next(); 13 | private byte[] token = SerializationUtils.serialize(OAuth2AccessTokenBuilder.oAuth2AccessTokenBuilder().build()); 14 | private String authenticationId = string().next(); 15 | private String username = string().next(); 16 | private String clientId = string().next(); 17 | 18 | private MongoOAuth2ClientTokenBuilder() { 19 | } 20 | 21 | public static MongoOAuth2ClientTokenBuilder mongoOAuth2ClientTokenBuilder() { 22 | return new MongoOAuth2ClientTokenBuilder(); 23 | } 24 | 25 | public MongoOAuth2ClientToken build() { 26 | return new MongoOAuth2ClientToken(id, 27 | tokenId, 28 | token, 29 | authenticationId, 30 | username, 31 | clientId); 32 | } 33 | 34 | public MongoOAuth2ClientTokenBuilder token(final OAuth2AccessToken token) { 35 | this.token = SerializationUtils.serialize(token); 36 | return this; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/MongoOAuth2RefreshTokenBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2RefreshToken; 4 | 5 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.string; 6 | 7 | public class MongoOAuth2RefreshTokenBuilder { 8 | 9 | private String tokenId = string().next(); 10 | private byte[] token = string().next().getBytes(); 11 | private byte[] authentication = string().next().getBytes(); 12 | 13 | private MongoOAuth2RefreshTokenBuilder() { 14 | } 15 | 16 | public static MongoOAuth2RefreshTokenBuilder mongoOAuth2RefreshTokenBuilder() { 17 | return new MongoOAuth2RefreshTokenBuilder(); 18 | } 19 | 20 | public MongoOAuth2RefreshToken build() { 21 | return new MongoOAuth2RefreshToken(tokenId, token, authentication); 22 | } 23 | 24 | public MongoOAuth2RefreshTokenBuilder token(final byte[] oAuth2RefreshTokenSer) { 25 | this.token = oAuth2RefreshTokenSer; 26 | return this; 27 | } 28 | 29 | public MongoOAuth2RefreshTokenBuilder authentication(final byte[] authenticationSer) { 30 | this.authentication = authenticationSer; 31 | return this; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/OAuth2AccessTokenBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; 4 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 5 | import org.springframework.security.oauth2.common.OAuth2RefreshToken; 6 | 7 | import java.time.LocalDateTime; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.*; 12 | import static uk.co.caeldev.springsecuritymongo.util.LocalDateTimeUtil.convertToDateFrom; 13 | 14 | public class OAuth2AccessTokenBuilder { 15 | 16 | private LocalDateTime expiration = localDateTime().next(); 17 | private OAuth2RefreshToken oAuth2RefreshToken = OAuth2RefreshTokenBuilder.oAuth2RefreshToken().build(); 18 | private Set scope = set(string()).next(); 19 | private Map additionalInformation = map(string(), objectOf(string())).next(); 20 | private String token = string().next(); 21 | 22 | private OAuth2AccessTokenBuilder() { 23 | } 24 | 25 | public static OAuth2AccessTokenBuilder oAuth2AccessTokenBuilder() { 26 | return new OAuth2AccessTokenBuilder(); 27 | } 28 | 29 | public OAuth2AccessToken build() { 30 | final DefaultOAuth2AccessToken oAuth2AccessToken = new DefaultOAuth2AccessToken(token); 31 | oAuth2AccessToken.setExpiration(convertToDateFrom(expiration)); 32 | oAuth2AccessToken.setRefreshToken(oAuth2RefreshToken); 33 | oAuth2AccessToken.setScope(scope); 34 | oAuth2AccessToken.setAdditionalInformation(additionalInformation); 35 | return oAuth2AccessToken; 36 | } 37 | 38 | public OAuth2AccessTokenBuilder token(String token) { 39 | this.token = token; 40 | return this; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/OAuth2AuthenticationBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.authentication.TestingAuthenticationToken; 4 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 5 | 6 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.string; 7 | import static uk.co.caeldev.springsecuritymongo.builders.OAuth2RequestBuilder.oAuth2RequestBuilder; 8 | 9 | public class OAuth2AuthenticationBuilder { 10 | 11 | private OAuth2AuthenticationBuilder() { 12 | } 13 | 14 | public static OAuth2AuthenticationBuilder oAuth2AuthenticationBuilder() { 15 | return new OAuth2AuthenticationBuilder(); 16 | } 17 | 18 | public OAuth2Authentication build() { 19 | return new OAuth2Authentication(oAuth2RequestBuilder().build(), new TestingAuthenticationToken(UserBuilder.userBuilder().build(), string().next())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/OAuth2ProtectedResourceDetailsBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails; 4 | import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; 5 | 6 | public class OAuth2ProtectedResourceDetailsBuilder { 7 | 8 | private OAuth2ProtectedResourceDetailsBuilder() { 9 | } 10 | 11 | public static OAuth2ProtectedResourceDetailsBuilder oAuth2ProtectedResourceDetailsBuilder() { 12 | return new OAuth2ProtectedResourceDetailsBuilder(); 13 | } 14 | 15 | public OAuth2ProtectedResourceDetails build() { 16 | return new BaseOAuth2ProtectedResourceDetails(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/OAuth2RefreshTokenBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken; 4 | import org.springframework.security.oauth2.common.OAuth2RefreshToken; 5 | 6 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.string; 7 | 8 | public class OAuth2RefreshTokenBuilder { 9 | 10 | private String value = string().next(); 11 | 12 | private OAuth2RefreshTokenBuilder() { 13 | } 14 | 15 | public static OAuth2RefreshTokenBuilder oAuth2RefreshToken() { 16 | return new OAuth2RefreshTokenBuilder(); 17 | } 18 | 19 | public OAuth2RefreshTokenBuilder value(String value) { 20 | this.value = value; 21 | return this; 22 | } 23 | 24 | public OAuth2RefreshToken build() { 25 | return new DefaultOAuth2RefreshToken(value); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/OAuth2RequestBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | import org.springframework.security.oauth2.provider.OAuth2Request; 5 | 6 | import java.io.Serializable; 7 | import java.util.Collection; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.*; 12 | 13 | public class OAuth2RequestBuilder { 14 | 15 | private Map requestParameters = map(string(), string()).next(); 16 | private String clientId = string().next(); 17 | private Collection authorities = list(ofGrantedAuthority()).next(); 18 | private boolean approved = bool().next(); 19 | private Set scope = set(string()).next(); 20 | private Set resourceIds = set(string()).next(); 21 | private String redirectUri = string().next(); 22 | private Set responseTypes = set(string()).next(); 23 | private Map extensionProperties = map(string(), serializableOf(longVal())).next(); 24 | 25 | private OAuth2RequestBuilder() { 26 | } 27 | 28 | public static OAuth2RequestBuilder oAuth2RequestBuilder() { 29 | return new OAuth2RequestBuilder(); 30 | } 31 | 32 | public OAuth2Request build() { 33 | return new OAuth2Request(requestParameters, 34 | clientId, 35 | authorities, 36 | approved, 37 | scope, 38 | resourceIds, 39 | redirectUri, 40 | responseTypes, 41 | extensionProperties); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/builders/UserBuilder.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.builders; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | import uk.co.caeldev.springsecuritymongo.domain.User; 5 | 6 | import java.util.Set; 7 | import java.util.UUID; 8 | 9 | import static uk.co.caeldev.springsecuritymongo.commons.SecurityRDG.*; 10 | 11 | public final class UserBuilder { 12 | 13 | private String password = string().next(); 14 | private String username = string().next(); 15 | private UUID userUUID = UUID.randomUUID(); 16 | private Set authorities = set(ofGrantedAuthority()).next(); 17 | private boolean accountNonExpired = bool().next(); 18 | private boolean accountNonLocked = bool().next(); 19 | private boolean credentialsNonExpired = bool().next(); 20 | private boolean enabled = bool().next(); 21 | 22 | private UserBuilder() { 23 | } 24 | 25 | public static UserBuilder userBuilder() { 26 | return new UserBuilder(); 27 | } 28 | 29 | public User build() { 30 | return new User( 31 | password, 32 | username, 33 | userUUID, 34 | authorities, 35 | accountNonExpired, 36 | accountNonLocked, 37 | credentialsNonExpired, 38 | enabled); 39 | } 40 | 41 | public UserBuilder username(final String username) { 42 | this.username = username; 43 | return this; 44 | } 45 | 46 | public UserBuilder password(final String password) { 47 | this.password = password; 48 | return this; 49 | } 50 | 51 | public UserBuilder authorities(final Set authorities) { 52 | this.authorities = authorities; 53 | return this; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/commons/SecurityRDG.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.commons; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 5 | import org.springframework.security.oauth2.provider.approval.Approval; 6 | import uk.co.caeldev.springsecuritymongo.builders.MongoApprovalBuilder; 7 | import uk.co.caeldev.springsecuritymongo.domain.MongoApproval; 8 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2AccessToken; 9 | import uk.org.fyodor.generators.Generator; 10 | import uk.org.fyodor.generators.characters.CharacterSetFilter; 11 | 12 | import java.io.Serializable; 13 | import java.time.LocalDateTime; 14 | 15 | import static uk.co.caeldev.springsecuritymongo.builders.ApprovalBuilder.approvalBuilder; 16 | import static uk.co.caeldev.springsecuritymongo.builders.MongoOAuth2AccessTokenBuilder.mongoOAuth2AccessTokenBuilder; 17 | 18 | public class SecurityRDG extends uk.org.fyodor.generators.RDG { 19 | 20 | public static Generator ofEscapedString() { 21 | return () -> string(30, CharacterSetFilter.LettersAndDigits).next(); 22 | } 23 | 24 | public static Generator ofGrantedAuthority() { 25 | return () -> new SimpleGrantedAuthority(string().next()); 26 | } 27 | 28 | public static Generator ofInvalidAuthority() { 29 | return () -> new SimpleGrantedAuthority(""); 30 | } 31 | 32 | public static Generator ofMongoOAuth2AccessToken() { 33 | return () -> mongoOAuth2AccessTokenBuilder().build(); 34 | } 35 | 36 | public static Generator objectOf(final Generator generator) { 37 | return () -> generator.next(); 38 | } 39 | 40 | public static Generator serializableOf(final Generator generator) { 41 | return () -> generator.next(); 42 | } 43 | 44 | public static Generator ofApproval() { 45 | return () -> approvalBuilder().build(); 46 | } 47 | 48 | public static Generator ofMongoApproval() { 49 | return () -> MongoApprovalBuilder.mongoApprovalBuilder().build(); 50 | } 51 | 52 | public static Generator localDateTime() { 53 | return () -> LocalDateTime.now().minusDays(longVal(30).next()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/config/ApplicationConfiguration.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.config; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | @EnableAutoConfiguration 9 | @EnableSecurityMongo 10 | public class ApplicationConfiguration { 11 | public static void main(String[] args) { 12 | SpringApplication.run(ApplicationConfiguration.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/config/MongoClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.config; 2 | 3 | import com.github.fakemongo.Fongo; 4 | import com.mongodb.MongoClient; 5 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.context.annotation.Profile; 9 | 10 | @Configuration 11 | @EnableConfigurationProperties(MongoSettings.class) 12 | @Profile("test") 13 | public class MongoClientConfiguration { 14 | 15 | @Bean 16 | public MongoClient mongoClient(MongoSettings mongoSettings) { 17 | Fongo fongo = new Fongo(mongoSettings.getDatabase()); 18 | return fongo.getMongo(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/repositories/AbstractRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.mongodb.MongoClient; 4 | import org.junit.Before; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.ActiveProfiles; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | import uk.co.caeldev.springsecuritymongo.config.ApplicationConfiguration; 11 | 12 | @RunWith(SpringRunner.class) 13 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { ApplicationConfiguration.class }) 14 | @ActiveProfiles("test") 15 | public abstract class AbstractRepositoryIntegrationTest { 16 | 17 | @Autowired 18 | protected MongoClient mongoClient; 19 | 20 | @Before 21 | public void dropDatabase() { 22 | mongoClient.dropDatabase("copyshare"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/repositories/MongoApprovalRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.google.common.collect.Lists; 4 | import org.junit.Test; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import uk.co.caeldev.springsecuritymongo.builders.MongoApprovalBuilder; 7 | import uk.co.caeldev.springsecuritymongo.domain.MongoApproval; 8 | 9 | import java.time.LocalDateTime; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | import static uk.org.fyodor.generators.RDG.string; 15 | 16 | public class MongoApprovalRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { 17 | 18 | @Autowired 19 | private MongoApprovalRepository mongoApprovalRepository; 20 | 21 | @Test 22 | public void shouldSaveMongoApproval() { 23 | //Given 24 | final String clientId = string().next(); 25 | final String userId = string().next(); 26 | final MongoApproval mongoApproval = MongoApprovalBuilder.mongoApprovalBuilder() 27 | .clientId(clientId).userId(userId).build(); 28 | 29 | //When 30 | mongoApprovalRepository.save(mongoApproval); 31 | 32 | //Then 33 | final List results = mongoApprovalRepository.findByUserIdAndClientId(userId, clientId); 34 | assertThat(results).isNotEmpty(); 35 | assertThat(results).hasSize(1); 36 | final MongoApproval approval = results.get(0); 37 | assertThat(approval).isEqualToComparingFieldByField(approval); 38 | } 39 | 40 | @Test 41 | public void shouldDeleteMongoApprovalByUserIdAndClientIdAndScope() { 42 | //Given 43 | final String clientId = "167181125test-approval-1237710666"; 44 | final String userId = "12d865f31941b6063aa9e315e092f113"; 45 | final String scope = "ADMIN"; 46 | 47 | //And 48 | final MongoApproval mongoApproval = MongoApprovalBuilder.mongoApprovalBuilder() 49 | .clientId(clientId).userId(userId).scope(scope).build(); 50 | mongoApprovalRepository.save(mongoApproval); 51 | 52 | //When 53 | mongoApprovalRepository.deleteByUserIdAndClientIdAndScope(mongoApproval); 54 | 55 | //Then 56 | final List results = mongoApprovalRepository.findByUserIdAndClientId(userId, clientId); 57 | assertThat(results).isEmpty(); 58 | } 59 | 60 | @Test 61 | public void shouldDeleteMongoApproval() { 62 | //Given 63 | final MongoApproval mongoApproval = MongoApprovalBuilder.mongoApprovalBuilder().build(); 64 | final MongoApproval mongoApprovalSaved = mongoApprovalRepository.save(mongoApproval); 65 | 66 | //When 67 | mongoApprovalRepository.delete(mongoApprovalSaved); 68 | 69 | //Then 70 | final List mongoApprovals = mongoApprovalRepository.findAll(); 71 | assertThat(mongoApprovals).isEmpty(); 72 | } 73 | 74 | @Test 75 | public void shouldUpdateExpiresAt() { 76 | //Given 77 | final LocalDateTime expiresAt = LocalDateTime.now(); 78 | final MongoApproval mongoApproval = MongoApprovalBuilder.mongoApprovalBuilder().build(); 79 | final MongoApproval mongoApprovalSaved = mongoApprovalRepository.save(mongoApproval); 80 | 81 | //When 82 | mongoApprovalRepository.updateExpiresAt(expiresAt, mongoApprovalSaved); 83 | 84 | //Then 85 | final List mongoApprovals = mongoApprovalRepository.findAll(); 86 | assertThat(mongoApprovals).hasSize(1); 87 | assertThat(mongoApprovals.get(0).getExpiresAt()).isEqualTo(expiresAt); 88 | } 89 | 90 | @Test 91 | public void shouldCreateOrUpdateACollectionOfMongoApprovals() { 92 | //Given 93 | final MongoApproval first = MongoApprovalBuilder.mongoApprovalBuilder().build(); 94 | final MongoApproval second = MongoApprovalBuilder.mongoApprovalBuilder().build(); 95 | final ArrayList approvals = Lists.newArrayList(first, second); 96 | 97 | //When 98 | final boolean result = mongoApprovalRepository.updateOrCreate(approvals); 99 | 100 | //Then 101 | assertThat(result).isTrue(); 102 | final List mongoApprovals = mongoApprovalRepository.findAll(); 103 | assertThat(mongoApprovals).hasSameSizeAs(approvals); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/repositories/MongoClientDetailsRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.google.common.collect.Sets; 4 | import org.junit.Test; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import uk.co.caeldev.springsecuritymongo.builders.MongoClientDetailsBuilder; 7 | import uk.co.caeldev.springsecuritymongo.domain.MongoClientDetails; 8 | 9 | import java.util.List; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | import static uk.org.fyodor.generators.RDG.string; 13 | 14 | public class MongoClientDetailsRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { 15 | 16 | @Autowired 17 | private MongoClientDetailsRepository mongoClientDetailsRepository; 18 | 19 | @Test 20 | public void shouldSaveMongoClientDetails() { 21 | //Given 22 | final MongoClientDetails mongoClientDetails = MongoClientDetailsBuilder.mongoClientDetailsBuilder().build(); 23 | 24 | //When 25 | final MongoClientDetails saved = mongoClientDetailsRepository.save(mongoClientDetails); 26 | 27 | //Then 28 | assertThat(saved).isEqualTo(mongoClientDetails); 29 | } 30 | 31 | @Test 32 | public void shouldDeleteMongoClientDetailsByClientId() { 33 | //Given 34 | final MongoClientDetails mongoClientDetails = MongoClientDetailsBuilder.mongoClientDetailsBuilder().build(); 35 | final MongoClientDetails saved = mongoClientDetailsRepository.save(mongoClientDetails); 36 | 37 | //When 38 | final boolean result = mongoClientDetailsRepository.deleteByClientId(saved.getClientId()); 39 | 40 | //Then 41 | assertThat(result).isTrue(); 42 | final List all = mongoClientDetailsRepository.findAll(); 43 | assertThat(all).isEmpty(); 44 | } 45 | 46 | @Test 47 | public void shouldUpdateClientSecret() { 48 | //Given 49 | final MongoClientDetails mongoClientDetails = MongoClientDetailsBuilder.mongoClientDetailsBuilder().build(); 50 | final MongoClientDetails saved = mongoClientDetailsRepository.save(mongoClientDetails); 51 | final String newSecret = string().next(); 52 | 53 | //When 54 | final boolean result = mongoClientDetailsRepository.updateClientSecret(saved.getClientId(), newSecret); 55 | 56 | //Then 57 | assertThat(result).isTrue(); 58 | final List all = mongoClientDetailsRepository.findAll(); 59 | assertThat(all).hasSize(1); 60 | final MongoClientDetails found = all.get(0); 61 | assertThat(found.getClientSecret()).isEqualTo(newSecret); 62 | } 63 | 64 | @Test 65 | public void shouldFindMongoClientDetailsByClientId() { 66 | //Given 67 | final MongoClientDetails mongoClientDetails = MongoClientDetailsBuilder.mongoClientDetailsBuilder().build(); 68 | final MongoClientDetails saved = mongoClientDetailsRepository.save(mongoClientDetails); 69 | 70 | //When 71 | final MongoClientDetails found = mongoClientDetailsRepository.findByClientId(saved.getClientId()); 72 | 73 | //Then 74 | assertThat(found).isNotNull(); 75 | assertThat(found).isEqualTo(saved); 76 | } 77 | 78 | @Test 79 | public void shouldUpdateFindMongoClientDetailsByClientId() { 80 | //Given 81 | final MongoClientDetails mongoClientDetails = MongoClientDetailsBuilder.mongoClientDetailsBuilder().build(); 82 | final MongoClientDetails saved = mongoClientDetailsRepository.save(mongoClientDetails); 83 | saved.setAutoApproveScopes(Sets.newHashSet("ADMIN")); 84 | 85 | //When 86 | final boolean result = mongoClientDetailsRepository.update(saved); 87 | 88 | //Then 89 | assertThat(result).isTrue(); 90 | } 91 | } -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2AccessTokenRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import com.mongodb.MongoClient; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import uk.co.caeldev.springsecuritymongo.builders.MongoOAuth2AccessTokenBuilder; 8 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2AccessToken; 9 | 10 | import java.util.List; 11 | 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | 14 | public class MongoOAuth2AccessTokenRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { 15 | 16 | @Autowired 17 | private MongoOAuth2AccessTokenRepository mongoOAuth2AccessTokenRepository; 18 | 19 | @Autowired 20 | private MongoClient mongoClient; 21 | 22 | @Before 23 | public void dropDatabase() { 24 | mongoClient.dropDatabase("copyshare"); 25 | } 26 | 27 | @Test 28 | public void shouldSaveToken() { 29 | //Given 30 | final MongoOAuth2AccessToken mongoOAuth2AccessToken = MongoOAuth2AccessTokenBuilder 31 | .mongoOAuth2AccessTokenBuilder().build(); 32 | 33 | //When 34 | final MongoOAuth2AccessToken saved = mongoOAuth2AccessTokenRepository.save(mongoOAuth2AccessToken); 35 | 36 | //Then 37 | assertThat(saved).isNotNull(); 38 | final List all = mongoOAuth2AccessTokenRepository.findAll(); 39 | assertThat(all).hasSize(1); 40 | } 41 | 42 | @Test 43 | public void shouldDeleteTokenByRefreshToken() { 44 | //Given 45 | final MongoOAuth2AccessToken mongoOAuth2AccessToken = MongoOAuth2AccessTokenBuilder 46 | .mongoOAuth2AccessTokenBuilder().build(); 47 | final MongoOAuth2AccessToken saved = mongoOAuth2AccessTokenRepository.save(mongoOAuth2AccessToken); 48 | 49 | //When 50 | final boolean result = mongoOAuth2AccessTokenRepository.deleteByRefreshTokenId(saved.getRefreshToken()); 51 | 52 | //Then 53 | assertThat(result).isTrue(); 54 | final List all = mongoOAuth2AccessTokenRepository.findAll(); 55 | assertThat(all).isEmpty(); 56 | } 57 | 58 | @Test 59 | public void shouldDeleteTokenById() { 60 | //Given 61 | final MongoOAuth2AccessToken mongoOAuth2AccessToken = MongoOAuth2AccessTokenBuilder 62 | .mongoOAuth2AccessTokenBuilder().build(); 63 | final MongoOAuth2AccessToken saved = mongoOAuth2AccessTokenRepository.save(mongoOAuth2AccessToken); 64 | 65 | //When 66 | final boolean result = mongoOAuth2AccessTokenRepository.deleteByTokenId(saved.getTokenId()); 67 | 68 | //Then 69 | assertThat(result).isTrue(); 70 | final List all = mongoOAuth2AccessTokenRepository.findAll(); 71 | assertThat(all).isEmpty(); 72 | } 73 | 74 | @Test 75 | public void shouldFindTokenById() { 76 | //Given 77 | final MongoOAuth2AccessToken mongoOAuth2AccessToken = MongoOAuth2AccessTokenBuilder 78 | .mongoOAuth2AccessTokenBuilder().build(); 79 | final MongoOAuth2AccessToken saved = mongoOAuth2AccessTokenRepository.save(mongoOAuth2AccessToken); 80 | 81 | //When 82 | final MongoOAuth2AccessToken result = mongoOAuth2AccessTokenRepository 83 | .findByTokenId(saved.getTokenId()); 84 | 85 | //Then 86 | assertThat(result).isNotNull(); 87 | } 88 | 89 | @Test 90 | public void shouldFindTokenByAuthenticationId() { 91 | //Given 92 | final MongoOAuth2AccessToken mongoOAuth2AccessToken = MongoOAuth2AccessTokenBuilder 93 | .mongoOAuth2AccessTokenBuilder().build(); 94 | final MongoOAuth2AccessToken saved = mongoOAuth2AccessTokenRepository.save(mongoOAuth2AccessToken); 95 | 96 | //When 97 | final MongoOAuth2AccessToken result = mongoOAuth2AccessTokenRepository 98 | .findByAuthenticationId(saved.getAuthenticationId()); 99 | 100 | //Then 101 | assertThat(result).isNotNull(); 102 | } 103 | 104 | @Test 105 | public void shouldFindAllTokensByClientId() { 106 | //Given 107 | final MongoOAuth2AccessToken mongoOAuth2AccessToken = MongoOAuth2AccessTokenBuilder 108 | .mongoOAuth2AccessTokenBuilder().build(); 109 | final MongoOAuth2AccessToken saved = mongoOAuth2AccessTokenRepository.save(mongoOAuth2AccessToken); 110 | 111 | //When 112 | final List tokens = mongoOAuth2AccessTokenRepository 113 | .findByClientId(saved.getClientId()); 114 | 115 | //Then 116 | assertThat(tokens).isNotNull(); 117 | assertThat(tokens).hasSize(1); 118 | } 119 | 120 | @Test 121 | public void shouldFindAllTokensByUsernameAndClientId() { 122 | //Given 123 | final MongoOAuth2AccessToken mongoOAuth2AccessToken = MongoOAuth2AccessTokenBuilder 124 | .mongoOAuth2AccessTokenBuilder().build(); 125 | final MongoOAuth2AccessToken saved = mongoOAuth2AccessTokenRepository.save(mongoOAuth2AccessToken); 126 | 127 | //When 128 | final List tokens = mongoOAuth2AccessTokenRepository 129 | .findByUsernameAndClientId(saved.getUsername(), saved.getClientId()); 130 | 131 | //Then 132 | assertThat(tokens).isNotNull(); 133 | assertThat(tokens).hasSize(1); 134 | } 135 | 136 | } -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2ClientTokenRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import org.junit.Test; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import uk.co.caeldev.springsecuritymongo.builders.MongoOAuth2ClientTokenBuilder; 6 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2ClientToken; 7 | 8 | import java.util.List; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | public class MongoOAuth2ClientTokenRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { 13 | 14 | @Autowired 15 | private MongoOAuth2ClientTokenRepository mongoOAuth2ClientTokenRepository; 16 | 17 | @Test 18 | public void shouldSaveMongoOAuth2ClientToken() { 19 | //Given 20 | final MongoOAuth2ClientToken mongoOAuth2ClientToken = MongoOAuth2ClientTokenBuilder 21 | .mongoOAuth2ClientTokenBuilder().build(); 22 | 23 | //When 24 | final MongoOAuth2ClientToken saved = mongoOAuth2ClientTokenRepository.save(mongoOAuth2ClientToken); 25 | 26 | //Then 27 | assertThat(saved).isEqualTo(mongoOAuth2ClientToken); 28 | } 29 | 30 | @Test 31 | public void shouldDeleteMongoOAuth2ClientTokenByAuthenticationId() { 32 | //Given 33 | final MongoOAuth2ClientToken mongoOAuth2ClientToken = MongoOAuth2ClientTokenBuilder 34 | .mongoOAuth2ClientTokenBuilder().build(); 35 | final MongoOAuth2ClientToken saved = mongoOAuth2ClientTokenRepository.save(mongoOAuth2ClientToken); 36 | 37 | //When 38 | final boolean result = mongoOAuth2ClientTokenRepository.deleteByAuthenticationId(saved.getAuthenticationId()); 39 | 40 | //Then 41 | assertThat(result).isTrue(); 42 | final List all = mongoOAuth2ClientTokenRepository.findAll(); 43 | assertThat(all).isEmpty(); 44 | } 45 | 46 | @Test 47 | public void shouldFindMongoOAuth2ClientTokenByAuthenticationId() { 48 | //Given 49 | final MongoOAuth2ClientToken mongoOAuth2ClientToken = MongoOAuth2ClientTokenBuilder 50 | .mongoOAuth2ClientTokenBuilder().build(); 51 | final MongoOAuth2ClientToken saved = mongoOAuth2ClientTokenRepository.save(mongoOAuth2ClientToken); 52 | 53 | //When 54 | final MongoOAuth2ClientToken found = mongoOAuth2ClientTokenRepository 55 | .findByAuthenticationId(saved.getAuthenticationId()); 56 | 57 | //Then 58 | assertThat(found).isNotNull(); 59 | assertThat(found).isEqualTo(saved); 60 | } 61 | } -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/repositories/MongoOAuth2RefreshTokenRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import org.junit.Test; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import uk.co.caeldev.springsecuritymongo.builders.MongoOAuth2RefreshTokenBuilder; 6 | import uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2RefreshToken; 7 | 8 | import java.util.List; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | public class MongoOAuth2RefreshTokenRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { 13 | 14 | @Autowired 15 | private MongoOAuth2RefreshTokenRepository mongoOAuth2RefreshTokenRepository; 16 | 17 | @Test 18 | public void shouldSaveRefreshToken() { 19 | //Given 20 | final MongoOAuth2RefreshToken mongoOAuth2RefreshToken = MongoOAuth2RefreshTokenBuilder.mongoOAuth2RefreshTokenBuilder().build(); 21 | 22 | //When 23 | final MongoOAuth2RefreshToken saved = mongoOAuth2RefreshTokenRepository.save(mongoOAuth2RefreshToken); 24 | 25 | //Then 26 | assertThat(saved).isNotNull(); 27 | assertThat(saved).isEqualTo(mongoOAuth2RefreshToken); 28 | } 29 | 30 | @Test 31 | public void shouldDeleteRefreshTokenByTokenId() { 32 | //Given 33 | final MongoOAuth2RefreshToken mongoOAuth2RefreshToken = MongoOAuth2RefreshTokenBuilder.mongoOAuth2RefreshTokenBuilder().build(); 34 | final MongoOAuth2RefreshToken saved = mongoOAuth2RefreshTokenRepository.save(mongoOAuth2RefreshToken); 35 | 36 | //When 37 | final boolean result = mongoOAuth2RefreshTokenRepository.deleteByTokenId(saved.getTokenId()); 38 | 39 | //Then 40 | assertThat(result).isTrue(); 41 | final List all = mongoOAuth2RefreshTokenRepository.findAll(); 42 | assertThat(all).isEmpty(); 43 | } 44 | 45 | @Test 46 | public void shouldFindRefreshTokenByTokenId() { 47 | //Given 48 | final MongoOAuth2RefreshToken mongoOAuth2RefreshToken = MongoOAuth2RefreshTokenBuilder.mongoOAuth2RefreshTokenBuilder().build(); 49 | final MongoOAuth2RefreshToken saved = mongoOAuth2RefreshTokenRepository.save(mongoOAuth2RefreshToken); 50 | 51 | //When 52 | final MongoOAuth2RefreshToken refreshedTokenFound = mongoOAuth2RefreshTokenRepository.findByTokenId(saved.getTokenId()); 53 | 54 | //Then 55 | assertThat(refreshedTokenFound).isNotNull(); 56 | assertThat(refreshedTokenFound).isEqualTo(saved); 57 | } 58 | } -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/repositories/UserRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.repositories; 2 | 3 | import org.junit.Test; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import uk.co.caeldev.springsecuritymongo.builders.UserBuilder; 6 | import uk.co.caeldev.springsecuritymongo.domain.User; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | import static uk.org.fyodor.generators.RDG.string; 13 | 14 | public class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest { 15 | 16 | @Autowired 17 | private UserRepository userRepository; 18 | 19 | @Test 20 | public void shouldSaveUser() { 21 | //Given 22 | final User user = UserBuilder.userBuilder().build(); 23 | 24 | //When 25 | final User result = userRepository.save(user); 26 | 27 | //Then 28 | Optional expectedUser = userRepository.findByUsername(user.getUsername()); 29 | assertThat(result).isEqualTo(expectedUser.get()); 30 | } 31 | 32 | @Test 33 | public void shouldChangePasswordUser() { 34 | //Given 35 | final User user = UserBuilder.userBuilder().build(); 36 | userRepository.save(user); 37 | 38 | //When 39 | final boolean result = userRepository.changePassword(user.getPassword(), string().next(), user.getUsername()); 40 | 41 | //Then 42 | assertThat(result).isTrue(); 43 | } 44 | 45 | @Test 46 | public void shouldFindUserByUsername() { 47 | //Given 48 | final User user = UserBuilder.userBuilder().build(); 49 | final User savedUser = userRepository.save(user); 50 | 51 | //When 52 | final Optional userFound = userRepository.findByUsername(user.getUsername()); 53 | 54 | //Then 55 | assertThat(userFound.isPresent()).isTrue(); 56 | assertThat(userFound.get()).isEqualTo(savedUser); 57 | } 58 | 59 | @Test 60 | public void shouldDeleteUserByUsername() { 61 | //Given 62 | final User user = UserBuilder.userBuilder().build(); 63 | final User savedUser = userRepository.save(user); 64 | 65 | //When 66 | userRepository.deleteByUsername(savedUser.getUsername()); 67 | 68 | //Then 69 | final List all = userRepository.findAll(); 70 | assertThat(all).isEmpty(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/uk/co/caeldev/springsecuritymongo/services/SecurityContextServiceTest.java: -------------------------------------------------------------------------------- 1 | package uk.co.caeldev.springsecuritymongo.services; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.springframework.security.authentication.TestingAuthenticationToken; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | import static uk.org.fyodor.generators.RDG.string; 9 | 10 | public class SecurityContextServiceTest { 11 | 12 | private SecurityContextService securityContextService; 13 | 14 | @Before 15 | public void setUp() { 16 | securityContextService = new SecurityContextService(); 17 | } 18 | 19 | @Test 20 | public void shouldSetAuthentication() { 21 | //Given 22 | final TestingAuthenticationToken authentication = new TestingAuthenticationToken(string().next(), new Object()); 23 | 24 | //When 25 | securityContextService.setAuthentication(authentication); 26 | 27 | //Then 28 | assertThat(securityContextService.getAuthentication()).isEqualTo(authentication); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | mongo: 2 | host: localhost 3 | port: 27017 4 | database: copyshare 5 | username: dev 6 | password: dev -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/samples/mongoAccessTokens.json: -------------------------------------------------------------------------------- 1 | { 2 | "mongoOAuth2AccessToken": { 3 | "data": [ 4 | { 5 | "_id" : "49d855f31931b6063aa9e315e092f17f", 6 | "_class" : "uk.co.caeldev.springsecuritymongo.domain.MongoOAuth2AccessToken", 7 | "token" : { "$binary" : "rO0ABXNyAENvcmcuc3ByaW5nZnJhbWV3b3JrLnNlY3VyaXR5Lm9hdXRoMi5jb21tb24uRGVmYXVsdE9BdXRoMkFjY2Vzc1Rva2VuDLKeNhsk+s4CAAZMABVhZGRpdGlvbmFsSW5mb3JtYXRpb250AA9MamF2YS91dGlsL01hcDtMAApleHBpcmF0aW9udAAQTGphdmEvdXRpbC9EYXRlO0wADHJlZnJlc2hUb2tlbnQAP0xvcmcvc3ByaW5nZnJhbWV3b3JrL3NlY3VyaXR5L29hdXRoMi9jb21tb24vT0F1dGgyUmVmcmVzaFRva2VuO0wABXNjb3BldAAPTGphdmEvdXRpbC9TZXQ7TAAJdG9rZW5UeXBldAASTGphdmEvbGFuZy9TdHJpbmc7TAAFdmFsdWVxAH4ABXhwc3IAHmphdmEudXRpbC5Db2xsZWN0aW9ucyRFbXB0eU1hcFk2FIVa3OfQAgAAeHBzcgAOamF2YS51dGlsLkRhdGVoaoEBS1l0GQMAAHhwdwgAAAFNsgoKo3hwc3IAJWphdmEudXRpbC5Db2xsZWN0aW9ucyRVbm1vZGlmaWFibGVTZXSAHZLRj5uAVQIAAHhyACxqYXZhLnV0aWwuQ29sbGVjdGlvbnMkVW5tb2RpZmlhYmxlQ29sbGVjdGlvbhlCAIDLXvceAgABTAABY3QAFkxqYXZhL3V0aWwvQ29sbGVjdGlvbjt4cHNyABdqYXZhLnV0aWwuTGlua2VkSGFzaFNldNhs11qV3SoeAgAAeHIAEWphdmEudXRpbC5IYXNoU2V0ukSFlZa4tzQDAAB4cHcMAAAAED9AAAAAAAABdAAEcmVhZHh0AAZiZWFyZXJ0ACRkN2YyYzFkZC05OGU0LTQwOGMtYTg4Yi1mN2ZhOGFhYWI2ZDc=", "$type" : 0 }, 8 | "authenticationId" : "ed7a9b82ec79668946f74ed5f6ba3277", 9 | "username" : "WQP}s!V8=.tLbU93m'+-icu,i,M", 10 | "clientId" : "292188125test-1237710585", 11 | "authentication" : { "$binary" : "rO0ABXNyAEFvcmcuc3ByaW5nZnJhbWV3b3JrLnNlY3VyaXR5Lm9hdXRoMi5wcm92aWRlci5PQXV0aDJBdXRoZW50aWNhdGlvbr1ACwIWYlITAgACTAANc3RvcmVkUmVxdWVzdHQAPExvcmcvc3ByaW5nZnJhbWV3b3JrL3NlY3VyaXR5L29hdXRoMi9wcm92aWRlci9PQXV0aDJSZXF1ZXN0O0wAEnVzZXJBdXRoZW50aWNhdGlvbnQAMkxvcmcvc3ByaW5nZnJhbWV3b3JrL3NlY3VyaXR5L2NvcmUvQXV0aGVudGljYXRpb247eHIAR29yZy5zcHJpbmdmcmFtZXdvcmsuc2VjdXJpdHkuYXV0aGVudGljYXRpb24uQWJzdHJhY3RBdXRoZW50aWNhdGlvblRva2Vu06oofm5HZA4CAANaAA1hdXRoZW50aWNhdGVkTAALYXV0aG9yaXRpZXN0ABZMamF2YS91dGlsL0NvbGxlY3Rpb247TAAHZGV0YWlsc3QAEkxqYXZhL2xhbmcvT2JqZWN0O3hwAHNyACZqYXZhLnV0aWwuQ29sbGVjdGlvbnMkVW5tb2RpZmlhYmxlTGlzdPwPJTG17I4QAgABTAAEbGlzdHQAEExqYXZhL3V0aWwvTGlzdDt4cgAsamF2YS51dGlsLkNvbGxlY3Rpb25zJFVubW9kaWZpYWJsZUNvbGxlY3Rpb24ZQgCAy173HgIAAUwAAWNxAH4ABHhwc3IAE2phdmEudXRpbC5BcnJheUxpc3R4gdIdmcdhnQMAAUkABHNpemV4cAAAAAF3BAAAAAFzcgBCb3JnLnNwcmluZ2ZyYW1ld29yay5zZWN1cml0eS5jb3JlLmF1dGhvcml0eS5TaW1wbGVHcmFudGVkQXV0aG9yaXR5AAAAAAAAAUACAAFMAARyb2xldAASTGphdmEvbGFuZy9TdHJpbmc7eHB0AAlST0xFX1VTRVJ4cQB+AAxwc3IAOm9yZy5zcHJpbmdmcmFtZXdvcmsuc2VjdXJpdHkub2F1dGgyLnByb3ZpZGVyLk9BdXRoMlJlcXVlc3QAAAAAAAAAAQIABloACGFwcHJvdmVkTAALYXV0aG9yaXRpZXNxAH4ABEwACmV4dGVuc2lvbnN0AA9MamF2YS91dGlsL01hcDtMAAtyZWRpcmVjdFVyaXEAfgAOTAALcmVzb3VyY2VJZHN0AA9MamF2YS91dGlsL1NldDtMAA1yZXNwb25zZVR5cGVzcQB+ABN4cgA4b3JnLnNwcmluZ2ZyYW1ld29yay5zZWN1cml0eS5vYXV0aDIucHJvdmlkZXIuQmFzZVJlcXVlc3Q2KHo+o3FpvQIAA0wACGNsaWVudElkcQB+AA5MABFyZXF1ZXN0UGFyYW1ldGVyc3EAfgASTAAFc2NvcGVxAH4AE3hwdAAYMjkyMTg4MTI1dGVzdC0xMjM3NzEwNTg1c3IAJWphdmEudXRpbC5Db2xsZWN0aW9ucyRVbm1vZGlmaWFibGVNYXDxpaj+dPUHQgIAAUwAAW1xAH4AEnhwc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAABncIAAAACAAAAAN0AApncmFudF90eXBldAAIcGFzc3dvcmR0AAljbGllbnRfaWR0ABgyOTIxODgxMjV0ZXN0LTEyMzc3MTA1ODV0AAh1c2VybmFtZXQAHldRUH1zPGI+IVY4PS50TGJVOTNtJystaWN1LGksTXhzcgAlamF2YS51dGlsLkNvbGxlY3Rpb25zJFVubW9kaWZpYWJsZVNldIAdktGPm4BVAgAAeHEAfgAJc3IAF2phdmEudXRpbC5MaW5rZWRIYXNoU2V02GzXWpXdKh4CAAB4cgARamF2YS51dGlsLkhhc2hTZXS6RIWVlri3NAMAAHhwdwwAAAAQP0AAAAAAAAF0AARyZWFkeAFzcQB+ACR3DAAAABA/QAAAAAAAAXNxAH4ADXQAC1JPTEVfQ0xJRU5UeHNxAH4AGT9AAAAAAAAAdwgAAAAQAAAAAHhwc3EAfgAjdwwAAAACP0AAAAAAAAF0AA9vYXV0aDItcmVzb3VyY2V4c3EAfgAkdwwAAAAQP0AAAAAAAAB4c3IAT29yZy5zcHJpbmdmcmFtZXdvcmsuc2VjdXJpdHkuYXV0aGVudGljYXRpb24uVXNlcm5hbWVQYXNzd29yZEF1dGhlbnRpY2F0aW9uVG9rZW4AAAAAAAABQAIAAkwAC2NyZWRlbnRpYWxzcQB+AAVMAAlwcmluY2lwYWxxAH4ABXhxAH4AAwFzcQB+AAdzcQB+AAsAAAABdwQAAAABcQB+AA94cQB+ADFzcgAXamF2YS51dGlsLkxpbmtlZEhhc2hNYXA0wE5cEGzA+wIAAVoAC2FjY2Vzc09yZGVyeHEAfgAZP0AAAAAAAAZ3CAAAAAgAAAADcQB+AB1xAH4AHnEAfgAbcQB+ABxxAH4AH3EAfgAgeABwc3IALXVrLmNvLmNhZWxkZXYuc3ByaW5nc2VjdXJpdHltb25nby5kb21haW4uVXNlcpb/s0k10H4LAgAIWgARYWNjb3VudE5vbkV4cGlyZWRaABBhY2NvdW50Tm9uTG9ja2VkWgAVY3JlZGVudGlhbHNOb25FeHBpcmVkWgAHZW5hYmxlZEwAC2F1dGhvcml0aWVzcQB+ABNMAAhwYXNzd29yZHEAfgAOTAAIdXNlclVVSUR0ABBMamF2YS91dGlsL1VVSUQ7TAAIdXNlcm5hbWVxAH4ADnhwAQEBAXNxAH4AI3cMAAAAAj9AAAAAAAABcQB+AA94cHNyAA5qYXZhLnV0aWwuVVVJRLyZA/eYbYUvAgACSgAMbGVhc3RTaWdCaXRzSgALbW9zdFNpZ0JpdHN4cKEHX9WlTLTF9EmdX9r8T8F0AB5XUVB9czxiPiFWOD0udExiVTkzbScrLWljdSxpLE0=", "$type" : 0 }, 12 | "refreshToken" : "49d855f31931b6063aa9e315e092f17f" 13 | } 14 | ] 15 | } 16 | } --------------------------------------------------------------------------------