├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src ├── main │ └── java │ │ └── com │ │ └── deg540 │ │ └── single_sign_on │ │ ├── sso │ │ ├── SSOToken.java │ │ ├── AuthenticationGateway.java │ │ ├── SingleSignOnRegistry.java │ │ ├── Response.java │ │ └── Request.java │ │ └── myservice │ │ └── MyService.java └── test │ └── java │ └── com │ └── deg540 │ └── single_sign_on │ └── MyServiceTest.java ├── .gitignore ├── Readme.md ├── gradlew.bat └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'single_sign_on' 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/540/single-sign-on-kata-java/master/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/com/deg540/single_sign_on/sso/SSOToken.java: -------------------------------------------------------------------------------- 1 | package com.deg540.single_sign_on.sso; 2 | 3 | public class SSOToken { 4 | 5 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/java/com/deg540/single_sign_on/sso/AuthenticationGateway.java: -------------------------------------------------------------------------------- 1 | package com.deg540.single_sign_on.sso; 2 | /** 3 | * Uses something like LDAP to determine if the given credentials are valid 4 | */ 5 | public interface AuthenticationGateway { 6 | boolean credentialsAreValid(String username, String password); 7 | } -------------------------------------------------------------------------------- /src/main/java/com/deg540/single_sign_on/sso/SingleSignOnRegistry.java: -------------------------------------------------------------------------------- 1 | package com.deg540.single_sign_on.sso; 2 | 3 | public interface SingleSignOnRegistry { 4 | 5 | SSOToken register_new_session(String userName, String password); 6 | boolean is_valid(SSOToken token); 7 | void unregister(SSOToken token); 8 | 9 | } -------------------------------------------------------------------------------- /src/main/java/com/deg540/single_sign_on/sso/Response.java: -------------------------------------------------------------------------------- 1 | package com.deg540.single_sign_on.sso; 2 | 3 | public class Response { 4 | 5 | private String text; 6 | 7 | public Response(String text) { 8 | this.text = text; 9 | } 10 | 11 | public String getText() { 12 | return this.text; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | *.DS_Store 3 | 4 | # Java class files 5 | *.class 6 | 7 | # Generated files 8 | bin/ 9 | gen/ 10 | 11 | # Gradle files 12 | .gradle/ 13 | build/ 14 | /*/build/ 15 | *.iml 16 | 17 | # Local configuration file (sdk path, etc) 18 | local.properties 19 | 20 | # Log Files 21 | *.log 22 | 23 | .idea/ 24 | -------------------------------------------------------------------------------- /src/main/java/com/deg540/single_sign_on/sso/Request.java: -------------------------------------------------------------------------------- 1 | package com.deg540.single_sign_on.sso; 2 | 3 | public class Request { 4 | 5 | private String name; 6 | private SSOToken token; 7 | 8 | public Request(String name, SSOToken token) { 9 | this.name = name; 10 | this.token = token; 11 | } 12 | 13 | public SSOToken getSSOToken() { 14 | return this.token; 15 | } 16 | 17 | public String getName() { 18 | return this.name; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/deg540/single_sign_on/MyServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.deg540.single_sign_on; 2 | 3 | import com.deg540.single_sign_on.myservice.MyService; 4 | import com.deg540.single_sign_on.sso.Request; 5 | import com.deg540.single_sign_on.sso.Response; 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.is; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class MyServiceTest { 13 | 14 | @Test 15 | public void invalidSSOTokenIsRejected() { 16 | MyService service = new MyService(null); 17 | 18 | Response response = service.handleRequest(new Request("Foo", null)); 19 | 20 | assertThat("hello Foo!", is(not(response.getText()))); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/deg540/single_sign_on/myservice/MyService.java: -------------------------------------------------------------------------------- 1 | package com.deg540.single_sign_on.myservice; 2 | 3 | import com.deg540.single_sign_on.sso.Request; 4 | import com.deg540.single_sign_on.sso.Response; 5 | import com.deg540.single_sign_on.sso.SSOToken; 6 | import com.deg540.single_sign_on.sso.SingleSignOnRegistry; 7 | 8 | public class MyService { 9 | 10 | private SingleSignOnRegistry registry; 11 | 12 | public MyService(SingleSignOnRegistry registry) { 13 | this.registry = registry; 14 | } 15 | 16 | public Response handleRequest(Request request) { 17 | // TODO: check request has a valid SSOToken 18 | return new Response("hello " + request.getName() + "!"); 19 | } 20 | 21 | public SSOToken handleRegister(String username, String password) { 22 | // TODO: register and return token 23 | return new SSOToken(); 24 | } 25 | 26 | public void handleUnRegister(SSOToken token) { 27 | // TODO: unregister token 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Single Sign On Kata 2 | 3 | A veces la seguridad es engorrosa. Tienes que acceder a una máquina por la mañana, después acceder a tu cliente de correo, luego acceder a la intranet corporativa, luego acceder a tu perfil privado, todo el rato accediendo a sitios introduciendo más y más usuarios y contraseñas. Hay varias formas de solucionar esto y en esta kata veremos una de ellas. 4 | 5 | Funciona de tal forma que la primera vez que accedes a un servicio, pones un usuario y una contraseña y el servicio las valida contra un registro central de usuarios y si son válidas el "Single Sign On Registry" te genera un token. Más tarde cuando quieres acceder a otro servicio, entregas el token en vez de tener que introducir de nuevo el usuario y la contraseña. El servicio puede comprobar con el "Sign On Registry" si el token es válido y si lo es, siplemente, te da acceso. Si el "Sign On Registry" no reconoce tu token, notificará al servicio y se te denegará la petición. 6 | 7 | En esta Kata, tu trabajo es desarrollar un nuevo servicio que use el "Single Sign on Registry". La funcionalidad actual del servicio es simple, dice "Hola Foo!" (o cualquiera que sea tu nombre) si tu token de acceso es válido. 8 | 9 | 10 | El "Single Sign On Registry" está desarrollado por otro equipo por lo que no podemos acceder a él. Pero tenemos la interfaz para el "Single Sign On Registry" para que podamos avanzar con nuestro servicio. 11 | 12 | ## Dobles de tests 13 | 14 | Esta kata es útil para prácticar la utilización de diferentes tipos de dobles de tests. 15 | 16 | ## Credits 17 | 18 | Esta es únicamente la versión java de la kata original. La kata original está publicada en [emilybache github](https://github.com/emilybache/Single-Sign-On-Kata) 19 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=`expr $i + 1` 158 | done 159 | case $i in 160 | 0) set -- ;; 161 | 1) set -- "$args0" ;; 162 | 2) set -- "$args0" "$args1" ;; 163 | 3) set -- "$args0" "$args1" "$args2" ;; 164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=`save "$@"` 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | exec "$JAVACMD" "$@" 184 | --------------------------------------------------------------------------------