From 88fd834d6bdce1b5795d1b323e8e613a1f7ff712 Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Fri, 2 Apr 2021 13:10:01 -0500 Subject: [PATCH] Remove samples Remove in favor of the spring-projects/spring-security-samples repository. Issue gh-9539 --- ...-security-samples-boot-hellorsocket.gradle | 11 - .../sample/HelloRSocketApplicationITests.java | 82 - .../java/sample/HelloRSocketApplication.java | 33 - .../sample/HelloRSocketSecurityConfig.java | 44 - .../main/java/sample/MessageController.java | 34 - .../src/main/resources/application.properties | 1 - ...ty-samples-boot-hellowebflux-method.gradle | 12 - .../HelloWebfluxMethodApplicationITests.java | 80 - .../sample/HelloWebfluxMethodApplication.java | 32 - .../java/sample/HelloWorldMessageService.java | 33 - .../main/java/sample/MessageController.java | 39 - .../src/main/java/sample/SecurityConfig.java | 58 - .../HelloWebfluxMethodApplicationTests.java | 132 - .../sample/HelloWorldMessageServiceTests.java | 60 - ...-security-samples-boot-hellowebflux.gradle | 11 - .../sample/HelloWebfluxApplicationITests.java | 78 - .../main/java/sample/HelloUserController.java | 44 - .../java/sample/HelloWebfluxApplication.java | 33 - .../sample/HelloWebfluxSecurityConfig.java | 41 - .../sample/HelloWebfluxApplicationTests.java | 114 - ...ecurity-samples-boot-hellowebfluxfn.gradle | 11 - .../HelloWebfluxFnApplicationITests.java | 84 - .../main/java/sample/HelloUserController.java | 45 - .../sample/HelloWebfluxFnApplication.java | 44 - .../sample/HelloWebfluxFnSecurityConfig.java | 41 - .../HelloWebfluxFnApplicationTests.java | 115 - ...ng-security-samples-boot-helloworld.gradle | 12 - .../samples/HelloWorldApplicationTests.java | 119 - .../samples/HelloWorldApplication.java | 33 - .../samples/config/SecurityConfig.java | 58 - .../security/samples/web/MainController.java | 55 - .../src/main/resources/application.yml | 12 - .../src/main/resources/static/css/main.css | 13 - .../src/main/resources/templates/index.html | 24 - .../src/main/resources/templates/login.html | 21 - .../main/resources/templates/user/index.html | 13 - ...ring-security-samples-boot-insecure.gradle | 8 - .../samples/InsecureApplicationTests.java | 48 - .../security/samples/InsecureApplication.java | 33 - .../security/samples/web/MainController.java | 62 - .../src/main/resources/application.yml | 11 - .../src/main/resources/static/css/main.css | 13 - .../src/main/resources/templates/index.html | 15 - .../src/main/resources/templates/login.html | 21 - .../main/resources/templates/user/index.html | 13 - ...ity-samples-boot-kotlin-webflux.gradle.kts | 41 - .../samples/KotlinWebfluxApplication.kt | 27 - .../security/samples/config/SecurityConfig.kt | 55 - .../security/samples/web/MainController.kt | 39 - .../src/main/resources/application.yml | 6 - .../src/main/resources/css/main.css | 8 - .../src/main/resources/templates/index.html | 24 - .../src/main/resources/templates/login.html | 20 - .../main/resources/templates/user/index.html | 13 - .../samples/KotlinWebfluxApplicationTests.kt | 67 - ...ng-security-samples-boot-kotlin.gradle.kts | 31 - .../security/samples/KotlinApplication.kt | 29 - .../security/samples/config/SecurityConfig.kt | 55 - .../security/samples/web/MainController.kt | 42 - .../kotlin/src/main/resources/application.yml | 6 - .../src/main/resources/static/css/main.css | 8 - .../src/main/resources/templates/index.html | 40 - .../src/main/resources/templates/login.html | 20 - .../main/resources/templates/user/index.html | 29 - .../samples/KotlinApplicationTests.kt | 85 - .../oauth2authorizationserver/README.adoc | 39 - ...ples-boot-oauth2authorizationserver.gradle | 14 - .../AuthorizationServerConfiguration.java | 284 - .../OAuth2AuthorizationServerApplication.java | 31 - .../src/main/resources/application.yml | 3 - ...h2AuthorizationServerApplicationTests.java | 65 - samples/boot/oauth2login-webflux/README.adoc | 324 - ...ty-samples-boot-oauth2login-webflux.gradle | 14 - .../sample/OAuth2LoginApplicationTests.java | 56 - .../ReactiveOAuth2LoginApplication.java | 32 - .../sample/web/OAuth2LoginController.java | 42 - .../src/main/resources/application.yml | 35 - .../src/main/resources/templates/index.html | 51 - .../sample/OAuth2LoginControllerTests.java | 83 - samples/boot/oauth2login/README.adoc | 321 - ...g-security-samples-boot-oauth2login.gradle | 14 - .../sample/OAuth2LoginApplicationTests.java | 385 -- .../java/sample/OAuth2LoginApplication.java | 31 - .../sample/web/OAuth2LoginController.java | 43 - .../src/main/resources/application.yml | 35 - .../src/main/resources/templates/index.html | 34 - .../web/OAuth2LoginControllerTests.java | 71 - .../boot/oauth2resourceserver-jwe/README.adoc | 119 - ...mples-boot-oauth2resourceserver-jwe.gradle | 13 - ...OAuth2ResourceServerApplicationITests.java | 100 - ...MockWebServerEnvironmentPostProcessor.java | 41 - .../boot/env/MockWebServerPropertySource.java | 122 - .../boot/env/package-info.java | 22 - .../OAuth2ResourceServerApplication.java | 31 - .../OAuth2ResourceServerController.java | 39 - ...h2ResourceServerSecurityConfiguration.java | 114 - .../main/resources/META-INF/spring.factories | 1 - .../src/main/resources/application.yml | 9 - .../src/main/resources/simple.priv | 28 - .../src/main/resources/simple.pub | 9 - .../README.adoc | 155 - ...t-oauth2resourceserver-multitenancy.gradle | 14 - ...OAuth2ResourceServerApplicationITests.java | 129 - ...MockWebServerEnvironmentPostProcessor.java | 41 - .../boot/env/MockWebServerPropertySource.java | 195 - .../boot/env/package-info.java | 22 - .../OAuth2ResourceServerApplication.java | 31 - .../OAuth2ResourceServerController.java | 41 - ...h2ResourceServerSecurityConfiguration.java | 49 - .../TenantAuthenticationManagerResolver.java | 58 - .../main/resources/META-INF/spring.factories | 1 - .../src/main/resources/application.yml | 10 - .../oauth2resourceserver-opaque/README.adoc | 114 - ...es-boot-oauth2resourceserver-opaque.gradle | 14 - ...OAuth2ResourceServerApplicationITests.java | 100 - ...MockWebServerEnvironmentPostProcessor.java | 41 - .../boot/env/MockWebServerPropertySource.java | 181 - .../boot/env/package-info.java | 23 - .../OAuth2ResourceServerApplication.java | 31 - .../OAuth2ResourceServerController.java | 45 - ...h2ResourceServerSecurityConfiguration.java | 55 - .../main/resources/META-INF/spring.factories | 1 - .../src/main/resources/application.yml | 8 - .../OAuth2ResourceServerControllerTests.java | 93 - .../oauth2resourceserver-static/README.adoc | 82 - ...es-boot-oauth2resourceserver-static.gradle | 12 - ...OAuth2ResourceServerApplicationITests.java | 100 - .../OAuth2ResourceServerApplication.java | 31 - .../OAuth2ResourceServerController.java | 39 - ...h2ResourceServerSecurityConfiguration.java | 60 - .../src/main/resources/application.yml | 6 - .../src/main/resources/simple.pub | 7 - .../oauth2resourceserver-webflux/README.adoc | 112 - ...s-boot-oauth2resourceserver-webflux.gradle | 16 - ...OAuth2ResourceServerApplicationITests.java | 77 - ...MockWebServerEnvironmentPostProcessor.java | 41 - .../boot/env/MockWebServerPropertySource.java | 121 - .../boot/env/package-info.java | 22 - .../OAuth2ResourceServerController.java | 46 - .../src/main/java/sample/SecurityConfig.java | 49 - ...ServerOAuth2ResourceServerApplication.java | 31 - .../main/resources/META-INF/spring.factories | 1 - .../src/main/resources/application.yml | 6 - .../OAuth2ResourceServerControllerTests.java | 110 - samples/boot/oauth2resourceserver/README.adoc | 126 - ...y-samples-boot-oauth2resourceserver.gradle | 13 - ...OAuth2ResourceServerApplicationITests.java | 123 - ...MockWebServerEnvironmentPostProcessor.java | 41 - .../boot/env/MockWebServerPropertySource.java | 121 - .../boot/env/package-info.java | 22 - .../OAuth2ResourceServerApplication.java | 31 - .../OAuth2ResourceServerController.java | 46 - ...h2ResourceServerSecurityConfiguration.java | 55 - .../main/resources/META-INF/spring.factories | 1 - .../src/main/resources/application.yml | 6 - .../OAuth2ResourceServerControllerTests.java | 96 - .../boot/oauth2webclient-webflux/README.adoc | 63 - ...amples-boot-oauth2webclient-webflux.gradle | 15 - .../OAuth2WebClientWebFluxApplication.java | 31 - .../java/sample/config/SecurityConfig.java | 58 - .../java/sample/config/WebClientConfig.java | 70 - .../main/java/sample/web/IndexController.java | 31 - .../sample/web/OAuth2WebClientController.java | 62 - ...teredOAuth2AuthorizedClientController.java | 66 - .../src/main/resources/application.yml | 21 - .../src/main/resources/templates/index.html | 51 - .../main/resources/templates/response.html | 31 - .../OAuth2WebClientControllerTests.java | 98 - ...Auth2WebClientWebFluxApplicationTests.java | 43 - ...OAuth2AuthorizedClientControllerTests.java | 98 - samples/boot/oauth2webclient/README.adoc | 63 - ...curity-samples-boot-oauth2webclient.gradle | 16 - .../sample/OAuth2WebClientApplication.java | 33 - .../java/sample/config/SecurityConfig.java | 58 - .../java/sample/config/WebClientConfig.java | 67 - .../main/java/sample/web/IndexController.java | 31 - .../sample/web/OAuth2WebClientController.java | 62 - ...teredOAuth2AuthorizedClientController.java | 65 - .../src/main/resources/application.yml | 21 - .../src/main/resources/templates/index.html | 51 - .../main/resources/templates/response.html | 31 - .../OAuth2WebClientApplicationTests.java | 46 - .../OAuth2WebClientControllerTests.java | 93 - ...OAuth2AuthorizedClientControllerTests.java | 93 - samples/boot/saml2login/README.adoc | 38 - ...ng-security-samples-boot-saml2login.gradle | 35 - .../sample/Saml2LoginApplicationITests.java | 99 - .../src/main/java/sample/IndexController.java | 36 - .../java/sample/Saml2LoginApplication.java | 29 - .../src/main/java/sample/SecurityConfig.java | 36 - .../src/main/resources/application.yml | 1 - .../src/main/resources/templates/index.html | 46 - ...-security-samples-boot-webflux-form.gradle | 36 - .../sample/WebfluxFormApplicationTests.java | 80 - .../java/sample/webdriver/IndexPage.java | 53 - .../java/sample/webdriver/LoginPage.java | 92 - .../src/main/java/sample/IndexController.java | 38 - .../java/sample/WebfluxFormApplication.java | 32 - .../sample/WebfluxFormSecurityConfig.java | 61 - .../src/main/resources/logback.xml | 12 - .../src/main/resources/templates/index.html | 17 - .../src/main/resources/templates/login.html | 32 - ...-security-samples-boot-webflux-x509.gradle | 11 - .../src/main/java/sample/MeController.java | 40 - .../java/sample/WebfluxX509Application.java | 61 - .../src/main/resources/application.yml | 8 - .../src/main/resources/certs/curl_app.sh | 2 - .../src/main/resources/certs/server.p12 | Bin 5255 -> 0 bytes .../sample/WebfluxX509ApplicationTest.java | 90 - samples/certificates/Readme.txt | 10 - samples/certificates/ca.pem | 22 - samples/certificates/dianne.p12 | Bin 1768 -> 0 bytes samples/certificates/localhost-with-ca/ca.crt | 13 - samples/certificates/localhost-with-ca/ca.csr | 11 - samples/certificates/localhost-with-ca/ca.key | 15 - .../certificates/localhost-with-ca/ca.key.org | 18 - .../localhost-with-ca/generate.sh | 13 - .../certificates/localhost-with-ca/tomcat.cer | 16 - .../certificates/localhost-with-ca/tomcat.csr | 15 - samples/certificates/rod.p12 | Bin 1784 -> 0 bytes samples/certificates/scott.p12 | Bin 1768 -> 0 bytes samples/certificates/server.jks | Bin 84658 -> 0 bytes ...security-samples-javaconfig-aspectj.gradle | 20 - .../sample/aspectj/AspectjSecurityConfig.java | 44 - .../java/sample/aspectj/SecuredService.java | 34 - .../src/main/java/sample/aspectj/Service.java | 38 - .../aspectj/AspectJInterceptorTests.java | 108 - .../src/test/resources/logback-test.xml | 15 - ...rity-samples-javaconfig-concurrency.gradle | 20 - ...sageSecurityWebApplicationInitializer.java | 35 - .../samples/config/SecurityConfig.java | 61 - .../samples/config/SecurityConfigTests.java | 35 - ...ng-security-samples-javaconfig-data.gradle | 12 - .../src/main/java/samples/DataConfig.java | 86 - .../src/main/java/samples/data/Message.java | 81 - .../java/samples/data/MessageRepository.java | 27 - .../data/SecurityMessageRepository.java | 31 - .../data/src/main/java/samples/data/User.java | 80 - .../data/SecurityMessageRepositoryTests.java | 72 - .../data/src/test/resources/data.sql | 10 - ...ng-security-samples-javaconfig-form.gradle | 40 - .../security/samples/FormJcTests.java | 78 - .../security/samples/pages/HomePage.java | 63 - .../security/samples/pages/LoginPage.java | 75 - ...sageSecurityWebApplicationInitializer.java | 28 - .../samples/config/SecurityConfig.java | 59 - .../form/src/main/resources/logback.xml | 12 - .../form/src/main/resources/views/login.html | 24 - .../src/main/webapp/WEB-INF/views/login.jspx | 36 - .../WEB-INF/views/messages/compose.jspx | 26 - .../webapp/WEB-INF/views/messages/inbox.jspx | 40 - .../webapp/WEB-INF/views/messages/show.jspx | 24 - .../samples/config/SecurityConfigTests.java | 35 - ...security-samples-javaconfig-hellojs.gradle | 20 - ...sageSecurityWebApplicationInitializer.java | 28 - .../samples/config/SecurityConfig.java | 35 - .../samples/mvc/MessageJsonController.java | 76 - .../main/resources/resources/js/bootstrap.js | 2280 ------- .../resources/js/jquery-3.5.1.min.js | 2 - .../resources/resources/js/knockout-2.3.0.js | 88 - .../main/resources/resources/js/message.js | 75 - .../main/resources/views/messages/inbox.html | 158 - .../src/main/webapp/META-INF/MANIFEST.MF | 2 - .../samples/config/SecurityConfigTests.java | 35 - ...ecurity-samples-javaconfig-hellomvc.gradle | 22 - ...sageSecurityWebApplicationInitializer.java | 30 - .../samples/config/SecurityConfig.java | 36 - .../src/main/resources/views/README.adoc | 0 .../src/main/webapp/META-INF/MANIFEST.MF | 2 - .../samples/config/SecurityConfigTests.java | 115 - ...urity-samples-javaconfig-helloworld.gradle | 29 - .../security/samples/HelloWorldJcTests.java | 78 - .../security/samples/pages/HomePage.java | 66 - .../security/samples/pages/LoginPage.java | 75 - .../samples/config/SecurityConfig.java | 36 - .../SecurityWebApplicationInitializer.java | 32 - .../helloworld/src/main/resources/logback.xml | 12 - .../src/main/webapp/META-INF/MANIFEST.MF | 2 - .../helloworld/src/main/webapp/index.jsp | 38 - .../resources/css/bootstrap-responsive.css | 1092 --- .../main/webapp/resources/css/bootstrap.css | 6039 ----------------- .../src/main/webapp/resources/img/favicon.ico | Bin 1150 -> 0 bytes .../src/main/webapp/resources/img/logo.png | Bin 1123 -> 0 bytes ...ecurity-samples-javaconfig-inmemory.gradle | 22 - ...sageSecurityWebApplicationInitializer.java | 28 - .../samples/config/SecurityConfig.java | 38 - .../src/main/webapp/META-INF/MANIFEST.MF | 2 - .../samples/config/SecurityConfigTests.java | 88 - ...ng-security-samples-javaconfig-jdbc.gradle | 41 - .../security/samples/JdbcJcTests.java | 80 - .../security/samples/pages/HomePage.java | 63 - .../security/samples/pages/LoginPage.java | 75 - ...sageSecurityWebApplicationInitializer.java | 28 - .../samples/config/SecurityConfig.java | 41 - .../jdbc/src/main/resources/logback.xml | 12 - .../jdbc/src/main/webapp/META-INF/MANIFEST.MF | 2 - ...ng-security-samples-javaconfig-ldap.gradle | 39 - .../security/samples/LdapJcTests.java | 82 - .../security/samples/pages/HomePage.java | 63 - .../security/samples/pages/LoginPage.java | 75 - ...sageSecurityWebApplicationInitializer.java | 28 - .../samples/config/SecurityConfig.java | 36 - .../ldap/src/main/resources/logback.xml | 12 - .../ldap/src/main/resources/users.ldif | 42 - .../ldap/src/main/webapp/META-INF/MANIFEST.MF | 2 - ...ecurity-samples-javaconfig-messages.gradle | 31 - .../src/main/java/META-INF/MANIFEST.MF | 3 - .../samples/config/DataConfiguration.java | 75 - .../MessageWebApplicationInitializer.java | 47 - .../samples/config/RootConfiguration.java | 26 - .../security/samples/data/Message.java | 73 - .../samples/data/MessageRepository.java | 28 - .../samples/mvc/DefaultController.java | 29 - .../samples/mvc/MessageController.java | 76 - .../mvc/config/WebMvcConfiguration.java | 88 - .../messages/src/main/resources/data.sql | 2 - .../resources/css/bootstrap-responsive.css | 1092 --- .../resources/resources/css/bootstrap.css | 6039 ----------------- .../main/resources/resources/img/favicon.ico | Bin 1150 -> 0 bytes .../src/main/resources/resources/img/logo.png | Bin 1123 -> 0 bytes .../src/main/resources/views/layout.html | 121 - .../resources/views/messages/compose.html | 40 - .../main/resources/views/messages/inbox.html | 29 - .../main/resources/views/messages/show.html | 20 - ...-security-samples-javaconfig-openid.gradle | 22 - ...sageSecurityWebApplicationInitializer.java | 31 - .../samples/config/SecurityConfig.java | 102 - .../security/samples/mvc/UserController.java | 39 - .../security/CustomUserDetailsService.java | 38 - .../openid/src/main/resources/logback.xml | 12 - .../main/resources/resources/css/openid.css | 45 - .../src/main/resources/resources/img/aol.gif | Bin 2205 -> 0 bytes .../main/resources/resources/img/blogger.ico | Bin 3638 -> 0 bytes .../main/resources/resources/img/claimid.ico | Bin 3638 -> 0 bytes .../main/resources/resources/img/facebook.gif | Bin 2075 -> 0 bytes .../main/resources/resources/img/favicon.ico | Bin 1150 -> 0 bytes .../main/resources/resources/img/flickr.ico | Bin 1150 -> 0 bytes .../main/resources/resources/img/google.gif | Bin 1596 -> 0 bytes .../resources/resources/img/livejournal.ico | Bin 5222 -> 0 bytes .../src/main/resources/resources/img/logo.png | Bin 1123 -> 0 bytes .../main/resources/resources/img/myopenid.ico | Bin 2862 -> 0 bytes .../resources/img/openid-inputicon.gif | Bin 237 -> 0 bytes .../main/resources/resources/img/openid.gif | Bin 740 -> 0 bytes .../resources/resources/img/technorati.ico | Bin 2294 -> 0 bytes .../main/resources/resources/img/verisign.gif | Bin 2550 -> 0 bytes .../main/resources/resources/img/verisign.ico | Bin 4710 -> 0 bytes .../main/resources/resources/img/vidoop.ico | Bin 1406 -> 0 bytes .../resources/resources/img/wordpress.ico | Bin 1150 -> 0 bytes .../main/resources/resources/img/yahoo.gif | Bin 1682 -> 0 bytes .../resources/js/jquery-1.2.6.min.js | 32 - .../js/openid-client/jquery.query-2.1.3.js | 220 - .../js/openid-client/openid-client-config.js | 20 - .../js/openid-client/openid-client.js | 63 - .../resources/resources/js/openid-jquery.js | 240 - .../openid/src/main/resources/users.ldif | 42 - .../src/main/resources/views/login.html | 51 - .../src/main/resources/views/user/show.html | 34 - .../src/main/resources/views/user/show.jspx | 42 - .../src/main/webapp/META-INF/MANIFEST.MF | 2 - .../samples/config/SecurityConfigTests.java | 48 - ...security-samples-javaconfig-preauth.gradle | 19 - ...sageSecurityWebApplicationInitializer.java | 28 - .../samples/config/SecurityConfig.java | 41 - .../preauth/src/main/resources/logback.xml | 12 - .../src/main/resources/views/login.html | 24 - .../src/main/webapp/META-INF/MANIFEST.MF | 2 - .../preauth/src/main/webapp/WEB-INF/web.xml | 35 - .../samples/config/SecurityConfigTests.java | 35 - ...urity-samples-javaconfig-rememberme.gradle | 19 - ...sageSecurityWebApplicationInitializer.java | 28 - .../samples/config/SecurityConfig.java | 58 - .../rememberme/src/main/resources/logback.xml | 12 - .../src/main/resources/views/login.html | 26 - .../src/main/webapp/META-INF/MANIFEST.MF | 2 - .../samples/config/SecurityConfigTests.java | 35 - ...urity-samples-javaconfig-saml2login.gradle | 13 - ...sageSecurityWebApplicationInitializer.java | 39 - .../samples/config/SecurityConfig.java | 91 - .../saml2login/src/main/resources/logback.xml | 12 - .../samples/config/SecurityConfigTests.java | 32 - ...ng-security-samples-javaconfig-x509.gradle | 19 - samples/javaconfig/x509/src/etc/ca.pem | 22 - samples/javaconfig/x509/src/etc/dianne.p12 | Bin 1768 -> 0 bytes samples/javaconfig/x509/src/etc/rod.p12 | Bin 1784 -> 0 bytes samples/javaconfig/x509/src/etc/scott.p12 | Bin 1768 -> 0 bytes samples/javaconfig/x509/src/etc/server.jks | Bin 84658 -> 0 bytes samples/javaconfig/x509/src/etc/server.xml | 46 - ...sageSecurityWebApplicationInitializer.java | 28 - .../samples/config/SecurityConfig.java | 53 - .../x509/src/main/resources/logback.xml | 12 - .../x509/src/main/webapp/META-INF/MANIFEST.MF | 2 - .../src/main/webapp/WEB-INF/decorators.xml | 5 - .../main/webapp/WEB-INF/decorators/main.jsp | 138 - .../src/main/webapp/WEB-INF/views/login.jspx | 36 - .../WEB-INF/views/messages/compose.jspx | 26 - .../webapp/WEB-INF/views/messages/inbox.jspx | 40 - .../webapp/WEB-INF/views/messages/show.jspx | 24 - .../x509/src/main/webapp/WEB-INF/web.xml- | 35 - .../samples/config/SecurityConfigTests.java | 35 - ...spring-security-samples-xml-aspectj.gradle | 16 - .../java/sample/aspectj/SecuredService.java | 34 - .../src/main/java/sample/aspectj/Service.java | 38 - .../src/main/resources/aspectj-context.xml | 48 - .../aspectj/AspectJInterceptorTests.java | 97 - .../src/test/resources/logback-test.xml | 15 - samples/xml/cas/Readme.txt | 12 - ...ring-security-samples-xml-cassample.gradle | 61 - .../samples/cas/CasSampleProxyTests.java | 148 - .../security/samples/cas/CasSampleTests.java | 158 - .../security/samples/cas/JettyCasService.java | 163 - .../samples/cas/pages/AccessDeniedPage.java | 53 - .../cas/pages/ExtremelySecurePage.java | 54 - .../security/samples/cas/pages/HomePage.java | 54 - .../samples/cas/pages/LocalLogoutPage.java | 34 - .../security/samples/cas/pages/LoginPage.java | 66 - .../security/samples/cas/pages/Page.java | 51 - .../cas/pages/ProxyTicketSamplePage.java | 54 - .../samples/cas/pages/SecurePage.java | 67 - .../samples/cas/pages/UnauthorizedPage.java | 52 - .../resources/logback-test.xml | 16 - .../cas/web/ProxyTicketSampleServlet.java | 90 - .../xml/cas/cassample/src/main/webapp/401.jsp | 8 - .../xml/cas/cassample/src/main/webapp/403.jsp | 8 - .../WEB-INF/applicationContext-security.xml | 124 - .../cassample/src/main/webapp/WEB-INF/web.xml | 89 - .../cassample/src/main/webapp/cas-logout.jsp | 15 - .../cassample/src/main/webapp/casfailed.jsp | 17 - .../cas/cassample/src/main/webapp/index.jsp | 12 - .../src/main/webapp/secure/extreme/index.jsp | 12 - .../src/main/webapp/secure/index.jsp | 15 - ...ring-security-samples-xml-casserver.gradle | 56 - .../src/main/webapp/WEB-INF/classes/log4j.xml | 17 - .../webapp/WEB-INF/deployerConfigContext.xml | 192 - .../applicationContext.xml | 149 - .../spring-security-samples-xml-cas.gradle | 25 - samples/xml/contacts/client/client.properties | 8 - samples/xml/contacts/client/clientContext.xml | 73 - ...pring-security-samples-xml-contacts.gradle | 43 - .../security/samples/ContactsTests.java | 93 - .../security/samples/pages/AddPage.java | 71 - .../security/samples/pages/ContactsPage.java | 131 - .../security/samples/pages/HomePage.java | 70 - .../security/samples/pages/LoginPage.java | 73 - .../contact/AddDeleteContactController.java | 79 - .../java/sample/contact/AddPermission.java | 57 - .../contact/AddPermissionValidator.java | 64 - .../contact/AdminPermissionController.java | 189 - .../sample/contact/ClientApplication.java | 153 - .../src/main/java/sample/contact/Contact.java | 92 - .../main/java/sample/contact/ContactDao.java | 42 - .../java/sample/contact/ContactDaoSpring.java | 96 - .../java/sample/contact/ContactManager.java | 57 - .../sample/contact/ContactManagerBackend.java | 194 - .../sample/contact/DataSourcePopulator.java | 276 - .../java/sample/contact/IndexController.java | 105 - .../main/java/sample/contact/WebContact.java | 46 - .../sample/contact/WebContactValidator.java | 49 - ...pplicationContext-common-authorization.xml | 66 - .../applicationContext-common-business.xml | 49 - .../resources/applicationContext-security.xml | 70 - .../contacts/src/main/resources/logback.xml | 14 - .../src/main/resources/messages.properties | 6 - .../main/webapp/WEB-INF/contacts-servlet.xml | 26 - .../src/main/webapp/WEB-INF/jsp/add.jsp | 42 - .../main/webapp/WEB-INF/jsp/addPermission.jsp | 56 - .../webapp/WEB-INF/jsp/adminPermission.jsp | 30 - .../webapp/WEB-INF/jsp/deletePermission.jsp | 20 - .../src/main/webapp/WEB-INF/jsp/deleted.jsp | 13 - .../src/main/webapp/WEB-INF/jsp/frames.jsp | 10 - .../src/main/webapp/WEB-INF/jsp/hello.jsp | 52 - .../src/main/webapp/WEB-INF/jsp/include.jsp | 6 - .../src/main/webapp/WEB-INF/jsp/index.jsp | 37 - .../main/webapp/WEB-INF/remoting-servlet.xml | 49 - .../src/main/webapp/WEB-INF/spring.tld | 311 - .../contacts/src/main/webapp/WEB-INF/web.xml | 99 - .../contacts/src/main/webapp/accessDenied.jsp | 22 - .../xml/contacts/src/main/webapp/error.html | 5 - .../xml/contacts/src/main/webapp/exitUser.jsp | 39 - .../xml/contacts/src/main/webapp/index.jsp | 4 - .../xml/contacts/src/main/webapp/login.jsp | 47 - .../contacts/src/main/webapp/secure/debug.jsp | 40 - .../contacts/src/main/webapp/switchUser.jsp | 42 - .../src/site/resources/logback-test.xml | 15 - .../contacts/src/site/resources/sslhowto.txt | 99 - .../sample/contact/ContactManagerTests.java | 173 - .../src/test/resources/logback-test.xml | 15 - .../spring-security-samples-xml-dms.gradle | 17 - .../main/java/sample/dms/AbstractElement.java | 100 - .../java/sample/dms/DataSourcePopulator.java | 166 - .../src/main/java/sample/dms/Directory.java | 40 - .../src/main/java/sample/dms/DocumentDao.java | 56 - .../main/java/sample/dms/DocumentDaoImpl.java | 136 - .../dms/src/main/java/sample/dms/File.java | 50 - .../secured/SecureDataSourcePopulator.java | 118 - .../sample/dms/secured/SecureDocumentDao.java | 32 - .../dms/secured/SecureDocumentDaoImpl.java | 73 - .../applicationContext-dms-insecure.xml | 40 - .../applicationContext-dms-secure.xml | 245 - .../applicationContext-dms-shared.xml | 18 - .../test/java/sample/DmsIntegrationTests.java | 160 - .../sample/SecureDmsIntegrationTests.java | 69 - .../dms/src/test/resources/logback-test.xml | 15 - samples/xml/gae/README.adoc | 5 - .../spring-security-samples-xml-gae.gradle | 44 - .../java/samples/gae/security/AppRole.java | 48 - .../gae/security/GaeAuthenticationFilter.java | 135 - .../gae/security/GaeUserAuthentication.java | 75 - ...oogleAccountsAuthenticationEntryPoint.java | 38 - .../GoogleAccountsAuthenticationProvider.java | 85 - .../gae/users/GaeDatastoreUserRegistry.java | 110 - .../main/java/samples/gae/users/GaeUser.java | 103 - .../gae/users/InMemoryUserRegistry.java | 51 - .../java/samples/gae/users/UserRegistry.java | 32 - .../java/samples/gae/validation/Forename.java | 39 - .../gae/validation/ForenameValidator.java | 35 - .../java/samples/gae/validation/Surname.java | 39 - .../gae/validation/SurnameValidator.java | 35 - .../samples/gae/web/GaeAppController.java | 66 - .../gae/web/RegistrationController.java | 79 - .../samples/gae/web/RegistrationForm.java | 46 - .../src/main/webapp/WEB-INF/appengine-web.xml | 11 - .../WEB-INF/applicationContext-security.xml | 48 - .../classes/ValidationMessages.properties | 2 - .../src/main/webapp/WEB-INF/gae-servlet.xml | 25 - .../src/main/webapp/WEB-INF/jsp/disabled.jsp | 16 - .../gae/src/main/webapp/WEB-INF/jsp/home.jsp | 26 - .../src/main/webapp/WEB-INF/jsp/landing.jsp | 33 - .../src/main/webapp/WEB-INF/jsp/loggedout.jsp | 17 - .../src/main/webapp/WEB-INF/jsp/register.jsp | 40 - .../main/webapp/WEB-INF/logging.properties | 5 - .../xml/gae/src/main/webapp/WEB-INF/web.xml | 46 - samples/xml/gae/src/main/webapp/favicon.ico | Bin 1150 -> 0 bytes .../gae/src/main/webapp/static/css/gae.css | 26 - .../samples/gae/security/AppRoleTests.java | 45 - .../users/GaeDataStoreUserRegistryTests.java | 70 - .../gae/src/test/resources/logback-test.xml | 15 - ...ing-security-samples-xml-helloworld.gradle | 33 - .../security/samples/HelloWorldXmlTests.java | 78 - .../security/samples/pages/HomePage.java | 66 - .../security/samples/pages/LoginPage.java | 75 - .../helloworld/src/main/resources/logback.xml | 12 - .../src/main/webapp/META-INF/MANIFEST.MF | 2 - .../main/webapp/WEB-INF/spring/security.xml | 11 - .../src/main/webapp/WEB-INF/web.xml | 36 - .../xml/helloworld/src/main/webapp/index.jsp | 38 - .../resources/css/bootstrap-responsive.css | 1092 --- .../main/webapp/resources/css/bootstrap.css | 6039 ----------------- .../src/main/webapp/resources/img/favicon.ico | Bin 1150 -> 0 bytes .../src/main/webapp/resources/img/logo.png | Bin 1123 -> 0 bytes ...pring-security-samples-xml-insecure.gradle | 28 - .../security/samples/HelloInsecureTests.java | 52 - .../security/samples/pages/HomePage.java | 55 - .../xml/insecure/src/main/java/README.adoc | 0 .../xml/insecure/src/main/webapp/index.jsp | 31 - .../resources/css/bootstrap-responsive.css | 1092 --- .../main/webapp/resources/css/bootstrap.css | 6039 ----------------- .../src/main/webapp/resources/img/favicon.ico | Bin 1150 -> 0 bytes .../src/main/webapp/resources/img/logo.png | Bin 1123 -> 0 bytes ...ng-security-samples-xml-insecuremvc.gradle | 17 - .../xml/insecuremvc/src/main/java/README.adoc | 0 .../src/main/webapp/META-INF/MANIFEST.MF | 2 - .../samples/config/SecurityConfigTests.java | 60 - .../src/test/resources/logback-test.xml | 15 - .../spring-security-samples-xml-jaas.gradle | 33 - .../security/samples/JaasXmlTests.java | 84 - .../security/samples/pages/HomePage.java | 69 - .../security/samples/pages/LoginPage.java | 77 - .../security/samples/pages/LogoutPage.java | 45 - .../security/samples/pages/SecurePage.java | 56 - .../jaas/RoleUserAuthorityGranter.java | 35 - .../UsernameEqualsPasswordLoginModule.java | 111 - .../resources/applicationContext-security.xml | 51 - .../xml/jaas/src/main/resources/logback.xml | 12 - .../xml/jaas/src/main/webapp/WEB-INF/web.xml | 63 - samples/xml/jaas/src/main/webapp/index.jsp | 24 - .../xml/jaas/src/main/webapp/secure/index.jsp | 58 - .../spring-security-samples-xml-ldap.gradle | 31 - .../security/samples/LdapXmlTests.java | 84 - .../security/samples/pages/HomePage.java | 69 - .../security/samples/pages/LoginPage.java | 77 - .../security/samples/pages/LogoutPage.java | 45 - .../security/samples/pages/SecurePage.java | 56 - .../xml/ldap/src/main/resources/logback.xml | 12 - .../xml/ldap/src/main/resources/users.ldif | 60 - .../WEB-INF/applicationContext-security.xml | 65 - .../xml/ldap/src/main/webapp/WEB-INF/web.xml | 44 - samples/xml/ldap/src/main/webapp/index.jsp | 12 - .../src/main/webapp/secure/extreme/index.jsp | 15 - .../xml/ldap/src/main/webapp/secure/index.jsp | 21 - samples/xml/oauth2login/README.adoc | 278 - ...ng-security-samples-xml-oauth2login.gradle | 15 - .../main/java/sample/config/WebConfig.java | 104 - .../sample/web/OAuth2LoginController.java | 42 - .../src/main/webapp/WEB-INF/security.xml | 52 - .../main/webapp/WEB-INF/spring-servlet.xml | 10 - .../main/webapp/WEB-INF/templates/index.html | 34 - .../src/main/webapp/WEB-INF/web.xml | 34 - .../spring-security-samples-xml-openid.gradle | 14 - .../samples/openid/CustomUserDetails.java | 65 - .../openid/CustomUserDetailsService.java | 129 - .../xml/openid/src/main/resources/logback.xml | 16 - .../WEB-INF/applicationContext-security.xml | 61 - .../openid/src/main/webapp/WEB-INF/web.xml | 44 - .../xml/openid/src/main/webapp/css/openid.css | 45 - .../xml/openid/src/main/webapp/images/aol.gif | Bin 2205 -> 0 bytes .../openid/src/main/webapp/images/blogger.ico | Bin 3638 -> 0 bytes .../openid/src/main/webapp/images/claimid.ico | Bin 3638 -> 0 bytes .../src/main/webapp/images/facebook.gif | Bin 2075 -> 0 bytes .../openid/src/main/webapp/images/flickr.ico | Bin 1150 -> 0 bytes .../openid/src/main/webapp/images/google.gif | Bin 1596 -> 0 bytes .../src/main/webapp/images/livejournal.ico | Bin 5222 -> 0 bytes .../src/main/webapp/images/myopenid.ico | Bin 2862 -> 0 bytes .../main/webapp/images/openid-inputicon.gif | Bin 237 -> 0 bytes .../openid/src/main/webapp/images/openid.gif | Bin 740 -> 0 bytes .../src/main/webapp/images/technorati.ico | Bin 2294 -> 0 bytes .../src/main/webapp/images/verisign.gif | Bin 2550 -> 0 bytes .../src/main/webapp/images/verisign.ico | Bin 4710 -> 0 bytes .../openid/src/main/webapp/images/vidoop.ico | Bin 1406 -> 0 bytes .../src/main/webapp/images/wordpress.ico | Bin 1150 -> 0 bytes .../openid/src/main/webapp/images/yahoo.gif | Bin 1682 -> 0 bytes samples/xml/openid/src/main/webapp/index.jsp | 38 - .../src/main/webapp/js/jquery-3.5.1.min.js | 2 - .../js/openid-client/jquery.query-2.1.3.js | 220 - .../js/openid-client/openid-client-config.js | 20 - .../webapp/js/openid-client/openid-client.js | 63 - .../src/main/webapp/js/openid-jquery.js | 240 - .../openid/src/main/webapp/openidlogin.jsp | 71 - samples/xml/preauth/realm.properties | 3 - ...spring-security-samples-xml-preauth.gradle | 16 - .../preauth/src/main/resources/logback.xml | 12 - .../WEB-INF/applicationContext-security.xml | 26 - .../preauth/src/main/webapp/WEB-INF/web.xml | 60 - samples/xml/preauth/src/main/webapp/index.jsp | 11 - .../src/main/webapp/secure/extreme/index.jsp | 10 - .../preauth/src/main/webapp/secure/index.jsp | 15 - .../src/test/java/sample/PreAuthXmlTests.java | 39 - .../src/test/resources/logback-test.xml | 15 - ...ing-security-samples-xml-servletapi.gradle | 21 - .../samples/servletapi/mvc/LoginForm.java | 43 - .../servletapi/mvc/ServletApiController.java | 211 - .../resources/applicationContext-security.xml | 20 - .../servletapi/src/main/resources/logback.xml | 12 - .../main/webapp/WEB-INF/spring-servlet.xml | 24 - .../src/main/webapp/WEB-INF/views/index.jsp | 44 - .../src/main/webapp/WEB-INF/views/login.jsp | 26 - .../src/main/webapp/WEB-INF/web.xml | 57 - samples/xml/tutorial/readme.txt | 10 - .../xml/tutorial/scripts/exec-list-as-peter | 5 - samples/xml/tutorial/scripts/exec-list-as-rod | 5 - .../xml/tutorial/scripts/exec-list-no-auth | 5 - .../tutorial/scripts/exec-list-wrong-password | 5 - .../xml/tutorial/scripts/exec-post-as-peter | 5 - samples/xml/tutorial/scripts/exec-post-as-rod | 5 - .../xml/tutorial/scripts/exec-post-no-auth | 5 - .../tutorial/scripts/exec-post-wrong-password | 5 - ...pring-security-samples-xml-tutorial.gradle | 16 - .../src/main/java/bigbank/Account.java | 74 - .../src/main/java/bigbank/BankDao.java | 25 - .../src/main/java/bigbank/BankDaoStub.java | 48 - .../src/main/java/bigbank/BankService.java | 30 - .../main/java/bigbank/BankServiceImpl.java | 50 - .../src/main/java/bigbank/SeedData.java | 37 - .../main/java/bigbank/web/ListAccounts.java | 53 - .../main/java/bigbank/web/PostAccounts.java | 57 - .../resources/applicationContext-business.xml | 24 - .../tutorial/src/main/resources/logback.xml | 12 - .../WEB-INF/applicationContext-security.xml | 64 - .../src/main/webapp/WEB-INF/bank-servlet.xml | 20 - .../main/webapp/WEB-INF/jsp/listAccounts.jsp | 58 - .../tutorial/src/main/webapp/WEB-INF/web.xml | 73 - .../xml/tutorial/src/main/webapp/index.jsp | 42 - .../tutorial/src/main/webapp/loggedout.jsp | 20 - .../src/main/webapp/secure/extreme/index.jsp | 29 - .../tutorial/src/main/webapp/secure/index.jsp | 53 - .../src/main/webapp/static/css/tutorial.css | 13 - .../xml/tutorial/src/main/webapp/timeout.jsp | 20 - 676 files changed, 61396 deletions(-) delete mode 100644 samples/boot/hellorsocket/spring-security-samples-boot-hellorsocket.gradle delete mode 100644 samples/boot/hellorsocket/src/integration-test/java/sample/HelloRSocketApplicationITests.java delete mode 100644 samples/boot/hellorsocket/src/main/java/sample/HelloRSocketApplication.java delete mode 100644 samples/boot/hellorsocket/src/main/java/sample/HelloRSocketSecurityConfig.java delete mode 100644 samples/boot/hellorsocket/src/main/java/sample/MessageController.java delete mode 100644 samples/boot/hellorsocket/src/main/resources/application.properties delete mode 100644 samples/boot/hellowebflux-method/spring-security-samples-boot-hellowebflux-method.gradle delete mode 100644 samples/boot/hellowebflux-method/src/integration-test/java/sample/HelloWebfluxMethodApplicationITests.java delete mode 100644 samples/boot/hellowebflux-method/src/main/java/sample/HelloWebfluxMethodApplication.java delete mode 100644 samples/boot/hellowebflux-method/src/main/java/sample/HelloWorldMessageService.java delete mode 100644 samples/boot/hellowebflux-method/src/main/java/sample/MessageController.java delete mode 100644 samples/boot/hellowebflux-method/src/main/java/sample/SecurityConfig.java delete mode 100644 samples/boot/hellowebflux-method/src/test/java/sample/HelloWebfluxMethodApplicationTests.java delete mode 100644 samples/boot/hellowebflux-method/src/test/java/sample/HelloWorldMessageServiceTests.java delete mode 100644 samples/boot/hellowebflux/spring-security-samples-boot-hellowebflux.gradle delete mode 100644 samples/boot/hellowebflux/src/integration-test/java/sample/HelloWebfluxApplicationITests.java delete mode 100644 samples/boot/hellowebflux/src/main/java/sample/HelloUserController.java delete mode 100644 samples/boot/hellowebflux/src/main/java/sample/HelloWebfluxApplication.java delete mode 100644 samples/boot/hellowebflux/src/main/java/sample/HelloWebfluxSecurityConfig.java delete mode 100644 samples/boot/hellowebflux/src/test/java/sample/HelloWebfluxApplicationTests.java delete mode 100644 samples/boot/hellowebfluxfn/spring-security-samples-boot-hellowebfluxfn.gradle delete mode 100644 samples/boot/hellowebfluxfn/src/integration-test/java/sample/HelloWebfluxFnApplicationITests.java delete mode 100644 samples/boot/hellowebfluxfn/src/main/java/sample/HelloUserController.java delete mode 100644 samples/boot/hellowebfluxfn/src/main/java/sample/HelloWebfluxFnApplication.java delete mode 100644 samples/boot/hellowebfluxfn/src/main/java/sample/HelloWebfluxFnSecurityConfig.java delete mode 100644 samples/boot/hellowebfluxfn/src/test/java/sample/HelloWebfluxFnApplicationTests.java delete mode 100644 samples/boot/helloworld/spring-security-samples-boot-helloworld.gradle delete mode 100644 samples/boot/helloworld/src/integration-test/java/org/springframework/security/samples/HelloWorldApplicationTests.java delete mode 100644 samples/boot/helloworld/src/main/java/org/springframework/security/samples/HelloWorldApplication.java delete mode 100644 samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/boot/helloworld/src/main/java/org/springframework/security/samples/web/MainController.java delete mode 100644 samples/boot/helloworld/src/main/resources/application.yml delete mode 100644 samples/boot/helloworld/src/main/resources/static/css/main.css delete mode 100644 samples/boot/helloworld/src/main/resources/templates/index.html delete mode 100644 samples/boot/helloworld/src/main/resources/templates/login.html delete mode 100644 samples/boot/helloworld/src/main/resources/templates/user/index.html delete mode 100644 samples/boot/insecure/spring-security-samples-boot-insecure.gradle delete mode 100644 samples/boot/insecure/src/integration-test/java/org/springframework/security/samples/InsecureApplicationTests.java delete mode 100644 samples/boot/insecure/src/main/java/org/springframework/security/samples/InsecureApplication.java delete mode 100644 samples/boot/insecure/src/main/java/org/springframework/security/samples/web/MainController.java delete mode 100644 samples/boot/insecure/src/main/resources/application.yml delete mode 100644 samples/boot/insecure/src/main/resources/static/css/main.css delete mode 100644 samples/boot/insecure/src/main/resources/templates/index.html delete mode 100644 samples/boot/insecure/src/main/resources/templates/login.html delete mode 100644 samples/boot/insecure/src/main/resources/templates/user/index.html delete mode 100644 samples/boot/kotlin-webflux/spring-security-samples-boot-kotlin-webflux.gradle.kts delete mode 100644 samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/KotlinWebfluxApplication.kt delete mode 100644 samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/config/SecurityConfig.kt delete mode 100644 samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/web/MainController.kt delete mode 100644 samples/boot/kotlin-webflux/src/main/resources/application.yml delete mode 100644 samples/boot/kotlin-webflux/src/main/resources/css/main.css delete mode 100644 samples/boot/kotlin-webflux/src/main/resources/templates/index.html delete mode 100644 samples/boot/kotlin-webflux/src/main/resources/templates/login.html delete mode 100644 samples/boot/kotlin-webflux/src/main/resources/templates/user/index.html delete mode 100644 samples/boot/kotlin-webflux/src/test/kotlin/org/springframework/security/samples/KotlinWebfluxApplicationTests.kt delete mode 100644 samples/boot/kotlin/spring-security-samples-boot-kotlin.gradle.kts delete mode 100644 samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/KotlinApplication.kt delete mode 100644 samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/config/SecurityConfig.kt delete mode 100644 samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/web/MainController.kt delete mode 100644 samples/boot/kotlin/src/main/resources/application.yml delete mode 100644 samples/boot/kotlin/src/main/resources/static/css/main.css delete mode 100644 samples/boot/kotlin/src/main/resources/templates/index.html delete mode 100644 samples/boot/kotlin/src/main/resources/templates/login.html delete mode 100644 samples/boot/kotlin/src/main/resources/templates/user/index.html delete mode 100644 samples/boot/kotlin/src/test/kotlin/org/springframework/security/samples/KotlinApplicationTests.kt delete mode 100644 samples/boot/oauth2authorizationserver/README.adoc delete mode 100644 samples/boot/oauth2authorizationserver/spring-security-samples-boot-oauth2authorizationserver.gradle delete mode 100644 samples/boot/oauth2authorizationserver/src/main/java/sample/AuthorizationServerConfiguration.java delete mode 100644 samples/boot/oauth2authorizationserver/src/main/java/sample/OAuth2AuthorizationServerApplication.java delete mode 100644 samples/boot/oauth2authorizationserver/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2authorizationserver/src/test/java/sample/OAuth2AuthorizationServerApplicationTests.java delete mode 100644 samples/boot/oauth2login-webflux/README.adoc delete mode 100644 samples/boot/oauth2login-webflux/spring-security-samples-boot-oauth2login-webflux.gradle delete mode 100644 samples/boot/oauth2login-webflux/src/integration-test/java/sample/OAuth2LoginApplicationTests.java delete mode 100644 samples/boot/oauth2login-webflux/src/main/java/sample/ReactiveOAuth2LoginApplication.java delete mode 100644 samples/boot/oauth2login-webflux/src/main/java/sample/web/OAuth2LoginController.java delete mode 100644 samples/boot/oauth2login-webflux/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2login-webflux/src/main/resources/templates/index.html delete mode 100644 samples/boot/oauth2login-webflux/src/test/java/sample/OAuth2LoginControllerTests.java delete mode 100644 samples/boot/oauth2login/README.adoc delete mode 100644 samples/boot/oauth2login/spring-security-samples-boot-oauth2login.gradle delete mode 100644 samples/boot/oauth2login/src/integration-test/java/sample/OAuth2LoginApplicationTests.java delete mode 100644 samples/boot/oauth2login/src/main/java/sample/OAuth2LoginApplication.java delete mode 100644 samples/boot/oauth2login/src/main/java/sample/web/OAuth2LoginController.java delete mode 100644 samples/boot/oauth2login/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2login/src/main/resources/templates/index.html delete mode 100644 samples/boot/oauth2login/src/test/java/sample/web/OAuth2LoginControllerTests.java delete mode 100644 samples/boot/oauth2resourceserver-jwe/README.adoc delete mode 100644 samples/boot/oauth2resourceserver-jwe/spring-security-samples-boot-oauth2resourceserver-jwe.gradle delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/package-info.java delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerApplication.java delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerController.java delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/resources/META-INF/spring.factories delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/resources/simple.priv delete mode 100644 samples/boot/oauth2resourceserver-jwe/src/main/resources/simple.pub delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/README.adoc delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/spring-security-samples-boot-oauth2resourceserver-multitenancy.gradle delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/package-info.java delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerApplication.java delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerController.java delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/TenantAuthenticationManagerResolver.java delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/main/resources/META-INF/spring.factories delete mode 100644 samples/boot/oauth2resourceserver-multitenancy/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2resourceserver-opaque/README.adoc delete mode 100644 samples/boot/oauth2resourceserver-opaque/spring-security-samples-boot-oauth2resourceserver-opaque.gradle delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/package-info.java delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerApplication.java delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerController.java delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/main/resources/META-INF/spring.factories delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2resourceserver-opaque/src/test/java/sample/OAuth2ResourceServerControllerTests.java delete mode 100644 samples/boot/oauth2resourceserver-static/README.adoc delete mode 100644 samples/boot/oauth2resourceserver-static/spring-security-samples-boot-oauth2resourceserver-static.gradle delete mode 100644 samples/boot/oauth2resourceserver-static/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java delete mode 100644 samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerApplication.java delete mode 100644 samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerController.java delete mode 100644 samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java delete mode 100644 samples/boot/oauth2resourceserver-static/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2resourceserver-static/src/main/resources/simple.pub delete mode 100644 samples/boot/oauth2resourceserver-webflux/README.adoc delete mode 100644 samples/boot/oauth2resourceserver-webflux/spring-security-samples-boot-oauth2resourceserver-webflux.gradle delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/integration-test/java/sample/ServerOAuth2ResourceServerApplicationITests.java delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/package-info.java delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/main/java/sample/OAuth2ResourceServerController.java delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/main/java/sample/SecurityConfig.java delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/main/java/sample/ServerOAuth2ResourceServerApplication.java delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/main/resources/META-INF/spring.factories delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2resourceserver-webflux/src/test/java/sample/OAuth2ResourceServerControllerTests.java delete mode 100644 samples/boot/oauth2resourceserver/README.adoc delete mode 100644 samples/boot/oauth2resourceserver/spring-security-samples-boot-oauth2resourceserver.gradle delete mode 100644 samples/boot/oauth2resourceserver/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java delete mode 100644 samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java delete mode 100644 samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java delete mode 100644 samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/package-info.java delete mode 100644 samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerApplication.java delete mode 100644 samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerController.java delete mode 100644 samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java delete mode 100644 samples/boot/oauth2resourceserver/src/main/resources/META-INF/spring.factories delete mode 100644 samples/boot/oauth2resourceserver/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2resourceserver/src/test/java/sample/OAuth2ResourceServerControllerTests.java delete mode 100644 samples/boot/oauth2webclient-webflux/README.adoc delete mode 100644 samples/boot/oauth2webclient-webflux/spring-security-samples-boot-oauth2webclient-webflux.gradle delete mode 100644 samples/boot/oauth2webclient-webflux/src/main/java/sample/OAuth2WebClientWebFluxApplication.java delete mode 100644 samples/boot/oauth2webclient-webflux/src/main/java/sample/config/SecurityConfig.java delete mode 100644 samples/boot/oauth2webclient-webflux/src/main/java/sample/config/WebClientConfig.java delete mode 100644 samples/boot/oauth2webclient-webflux/src/main/java/sample/web/IndexController.java delete mode 100644 samples/boot/oauth2webclient-webflux/src/main/java/sample/web/OAuth2WebClientController.java delete mode 100644 samples/boot/oauth2webclient-webflux/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java delete mode 100644 samples/boot/oauth2webclient-webflux/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2webclient-webflux/src/main/resources/templates/index.html delete mode 100644 samples/boot/oauth2webclient-webflux/src/main/resources/templates/response.html delete mode 100644 samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientControllerTests.java delete mode 100644 samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientWebFluxApplicationTests.java delete mode 100644 samples/boot/oauth2webclient-webflux/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java delete mode 100644 samples/boot/oauth2webclient/README.adoc delete mode 100644 samples/boot/oauth2webclient/spring-security-samples-boot-oauth2webclient.gradle delete mode 100644 samples/boot/oauth2webclient/src/main/java/sample/OAuth2WebClientApplication.java delete mode 100644 samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java delete mode 100644 samples/boot/oauth2webclient/src/main/java/sample/config/WebClientConfig.java delete mode 100644 samples/boot/oauth2webclient/src/main/java/sample/web/IndexController.java delete mode 100644 samples/boot/oauth2webclient/src/main/java/sample/web/OAuth2WebClientController.java delete mode 100644 samples/boot/oauth2webclient/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java delete mode 100644 samples/boot/oauth2webclient/src/main/resources/application.yml delete mode 100644 samples/boot/oauth2webclient/src/main/resources/templates/index.html delete mode 100644 samples/boot/oauth2webclient/src/main/resources/templates/response.html delete mode 100644 samples/boot/oauth2webclient/src/test/java/sample/OAuth2WebClientApplicationTests.java delete mode 100644 samples/boot/oauth2webclient/src/test/java/sample/OAuth2WebClientControllerTests.java delete mode 100644 samples/boot/oauth2webclient/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java delete mode 100644 samples/boot/saml2login/README.adoc delete mode 100644 samples/boot/saml2login/spring-security-samples-boot-saml2login.gradle delete mode 100644 samples/boot/saml2login/src/integration-test/java/sample/Saml2LoginApplicationITests.java delete mode 100644 samples/boot/saml2login/src/main/java/sample/IndexController.java delete mode 100644 samples/boot/saml2login/src/main/java/sample/Saml2LoginApplication.java delete mode 100644 samples/boot/saml2login/src/main/java/sample/SecurityConfig.java delete mode 100644 samples/boot/saml2login/src/main/resources/application.yml delete mode 100644 samples/boot/saml2login/src/main/resources/templates/index.html delete mode 100644 samples/boot/webflux-form/spring-security-samples-boot-webflux-form.gradle delete mode 100644 samples/boot/webflux-form/src/integration-test/java/sample/WebfluxFormApplicationTests.java delete mode 100644 samples/boot/webflux-form/src/integration-test/java/sample/webdriver/IndexPage.java delete mode 100644 samples/boot/webflux-form/src/integration-test/java/sample/webdriver/LoginPage.java delete mode 100644 samples/boot/webflux-form/src/main/java/sample/IndexController.java delete mode 100644 samples/boot/webflux-form/src/main/java/sample/WebfluxFormApplication.java delete mode 100644 samples/boot/webflux-form/src/main/java/sample/WebfluxFormSecurityConfig.java delete mode 100644 samples/boot/webflux-form/src/main/resources/logback.xml delete mode 100644 samples/boot/webflux-form/src/main/resources/templates/index.html delete mode 100644 samples/boot/webflux-form/src/main/resources/templates/login.html delete mode 100644 samples/boot/webflux-x509/spring-security-samples-boot-webflux-x509.gradle delete mode 100644 samples/boot/webflux-x509/src/main/java/sample/MeController.java delete mode 100644 samples/boot/webflux-x509/src/main/java/sample/WebfluxX509Application.java delete mode 100644 samples/boot/webflux-x509/src/main/resources/application.yml delete mode 100644 samples/boot/webflux-x509/src/main/resources/certs/curl_app.sh delete mode 100644 samples/boot/webflux-x509/src/main/resources/certs/server.p12 delete mode 100644 samples/boot/webflux-x509/src/test/java/sample/WebfluxX509ApplicationTest.java delete mode 100644 samples/certificates/Readme.txt delete mode 100644 samples/certificates/ca.pem delete mode 100755 samples/certificates/dianne.p12 delete mode 100644 samples/certificates/localhost-with-ca/ca.crt delete mode 100644 samples/certificates/localhost-with-ca/ca.csr delete mode 100644 samples/certificates/localhost-with-ca/ca.key delete mode 100644 samples/certificates/localhost-with-ca/ca.key.org delete mode 100644 samples/certificates/localhost-with-ca/generate.sh delete mode 100644 samples/certificates/localhost-with-ca/tomcat.cer delete mode 100644 samples/certificates/localhost-with-ca/tomcat.csr delete mode 100755 samples/certificates/rod.p12 delete mode 100644 samples/certificates/scott.p12 delete mode 100755 samples/certificates/server.jks delete mode 100644 samples/javaconfig/aspectj/spring-security-samples-javaconfig-aspectj.gradle delete mode 100644 samples/javaconfig/aspectj/src/main/java/sample/aspectj/AspectjSecurityConfig.java delete mode 100644 samples/javaconfig/aspectj/src/main/java/sample/aspectj/SecuredService.java delete mode 100644 samples/javaconfig/aspectj/src/main/java/sample/aspectj/Service.java delete mode 100644 samples/javaconfig/aspectj/src/test/java/sample/aspectj/AspectJInterceptorTests.java delete mode 100644 samples/javaconfig/aspectj/src/test/resources/logback-test.xml delete mode 100644 samples/javaconfig/concurrency/spring-security-samples-javaconfig-concurrency.gradle delete mode 100644 samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/concurrency/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/javaconfig/data/spring-security-samples-javaconfig-data.gradle delete mode 100644 samples/javaconfig/data/src/main/java/samples/DataConfig.java delete mode 100644 samples/javaconfig/data/src/main/java/samples/data/Message.java delete mode 100644 samples/javaconfig/data/src/main/java/samples/data/MessageRepository.java delete mode 100644 samples/javaconfig/data/src/main/java/samples/data/SecurityMessageRepository.java delete mode 100644 samples/javaconfig/data/src/main/java/samples/data/User.java delete mode 100644 samples/javaconfig/data/src/test/java/samples/data/SecurityMessageRepositoryTests.java delete mode 100644 samples/javaconfig/data/src/test/resources/data.sql delete mode 100644 samples/javaconfig/form/spring-security-samples-javaconfig-form.gradle delete mode 100644 samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/FormJcTests.java delete mode 100644 samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java delete mode 100644 samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java delete mode 100644 samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/form/src/main/resources/logback.xml delete mode 100644 samples/javaconfig/form/src/main/resources/views/login.html delete mode 100644 samples/javaconfig/form/src/main/webapp/WEB-INF/views/login.jspx delete mode 100644 samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/compose.jspx delete mode 100644 samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/inbox.jspx delete mode 100644 samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/show.jspx delete mode 100644 samples/javaconfig/form/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/javaconfig/hellojs/spring-security-samples-javaconfig-hellojs.gradle delete mode 100644 samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/mvc/MessageJsonController.java delete mode 100644 samples/javaconfig/hellojs/src/main/resources/resources/js/bootstrap.js delete mode 100644 samples/javaconfig/hellojs/src/main/resources/resources/js/jquery-3.5.1.min.js delete mode 100644 samples/javaconfig/hellojs/src/main/resources/resources/js/knockout-2.3.0.js delete mode 100644 samples/javaconfig/hellojs/src/main/resources/resources/js/message.js delete mode 100644 samples/javaconfig/hellojs/src/main/resources/views/messages/inbox.html delete mode 100644 samples/javaconfig/hellojs/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/hellojs/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/javaconfig/hellomvc/spring-security-samples-javaconfig-hellomvc.gradle delete mode 100644 samples/javaconfig/hellomvc/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/hellomvc/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/hellomvc/src/main/resources/views/README.adoc delete mode 100644 samples/javaconfig/hellomvc/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/hellomvc/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/javaconfig/helloworld/spring-security-samples-javaconfig-helloworld.gradle delete mode 100644 samples/javaconfig/helloworld/src/integration-test/java/org/springframework/security/samples/HelloWorldJcTests.java delete mode 100644 samples/javaconfig/helloworld/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java delete mode 100644 samples/javaconfig/helloworld/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java delete mode 100644 samples/javaconfig/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/helloworld/src/main/java/org/springframework/security/samples/config/SecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/helloworld/src/main/resources/logback.xml delete mode 100644 samples/javaconfig/helloworld/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/helloworld/src/main/webapp/index.jsp delete mode 100644 samples/javaconfig/helloworld/src/main/webapp/resources/css/bootstrap-responsive.css delete mode 100644 samples/javaconfig/helloworld/src/main/webapp/resources/css/bootstrap.css delete mode 100644 samples/javaconfig/helloworld/src/main/webapp/resources/img/favicon.ico delete mode 100644 samples/javaconfig/helloworld/src/main/webapp/resources/img/logo.png delete mode 100644 samples/javaconfig/inmemory/spring-security-samples-javaconfig-inmemory.gradle delete mode 100644 samples/javaconfig/inmemory/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/inmemory/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/inmemory/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/inmemory/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/javaconfig/jdbc/spring-security-samples-javaconfig-jdbc.gradle delete mode 100644 samples/javaconfig/jdbc/src/integration-test/java/org/springframework/security/samples/JdbcJcTests.java delete mode 100644 samples/javaconfig/jdbc/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java delete mode 100644 samples/javaconfig/jdbc/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java delete mode 100644 samples/javaconfig/jdbc/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/jdbc/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/jdbc/src/main/resources/logback.xml delete mode 100644 samples/javaconfig/jdbc/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/ldap/spring-security-samples-javaconfig-ldap.gradle delete mode 100644 samples/javaconfig/ldap/src/integration-test/java/org/springframework/security/samples/LdapJcTests.java delete mode 100644 samples/javaconfig/ldap/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java delete mode 100644 samples/javaconfig/ldap/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java delete mode 100644 samples/javaconfig/ldap/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/ldap/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/ldap/src/main/resources/logback.xml delete mode 100644 samples/javaconfig/ldap/src/main/resources/users.ldif delete mode 100644 samples/javaconfig/ldap/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/messages/spring-security-samples-javaconfig-messages.gradle delete mode 100644 samples/javaconfig/messages/src/main/java/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/messages/src/main/java/org/springframework/security/samples/config/DataConfiguration.java delete mode 100644 samples/javaconfig/messages/src/main/java/org/springframework/security/samples/config/MessageWebApplicationInitializer.java delete mode 100644 samples/javaconfig/messages/src/main/java/org/springframework/security/samples/config/RootConfiguration.java delete mode 100644 samples/javaconfig/messages/src/main/java/org/springframework/security/samples/data/Message.java delete mode 100644 samples/javaconfig/messages/src/main/java/org/springframework/security/samples/data/MessageRepository.java delete mode 100644 samples/javaconfig/messages/src/main/java/org/springframework/security/samples/mvc/DefaultController.java delete mode 100644 samples/javaconfig/messages/src/main/java/org/springframework/security/samples/mvc/MessageController.java delete mode 100644 samples/javaconfig/messages/src/main/java/org/springframework/security/samples/mvc/config/WebMvcConfiguration.java delete mode 100644 samples/javaconfig/messages/src/main/resources/data.sql delete mode 100644 samples/javaconfig/messages/src/main/resources/resources/css/bootstrap-responsive.css delete mode 100644 samples/javaconfig/messages/src/main/resources/resources/css/bootstrap.css delete mode 100644 samples/javaconfig/messages/src/main/resources/resources/img/favicon.ico delete mode 100644 samples/javaconfig/messages/src/main/resources/resources/img/logo.png delete mode 100644 samples/javaconfig/messages/src/main/resources/views/layout.html delete mode 100644 samples/javaconfig/messages/src/main/resources/views/messages/compose.html delete mode 100644 samples/javaconfig/messages/src/main/resources/views/messages/inbox.html delete mode 100644 samples/javaconfig/messages/src/main/resources/views/messages/show.html delete mode 100644 samples/javaconfig/openid/spring-security-samples-javaconfig-openid.gradle delete mode 100644 samples/javaconfig/openid/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/openid/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/openid/src/main/java/org/springframework/security/samples/mvc/UserController.java delete mode 100644 samples/javaconfig/openid/src/main/java/org/springframework/security/samples/security/CustomUserDetailsService.java delete mode 100644 samples/javaconfig/openid/src/main/resources/logback.xml delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/css/openid.css delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/aol.gif delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/blogger.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/claimid.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/facebook.gif delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/favicon.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/flickr.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/google.gif delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/livejournal.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/logo.png delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/myopenid.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/openid-inputicon.gif delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/openid.gif delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/technorati.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/verisign.gif delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/verisign.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/vidoop.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/wordpress.ico delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/img/yahoo.gif delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/js/jquery-1.2.6.min.js delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/js/openid-client/jquery.query-2.1.3.js delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/js/openid-client/openid-client-config.js delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/js/openid-client/openid-client.js delete mode 100644 samples/javaconfig/openid/src/main/resources/resources/js/openid-jquery.js delete mode 100644 samples/javaconfig/openid/src/main/resources/users.ldif delete mode 100644 samples/javaconfig/openid/src/main/resources/views/login.html delete mode 100644 samples/javaconfig/openid/src/main/resources/views/user/show.html delete mode 100644 samples/javaconfig/openid/src/main/resources/views/user/show.jspx delete mode 100644 samples/javaconfig/openid/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/openid/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/javaconfig/preauth/spring-security-samples-javaconfig-preauth.gradle delete mode 100644 samples/javaconfig/preauth/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/preauth/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/preauth/src/main/resources/logback.xml delete mode 100644 samples/javaconfig/preauth/src/main/resources/views/login.html delete mode 100644 samples/javaconfig/preauth/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/preauth/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/javaconfig/preauth/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/javaconfig/rememberme/spring-security-samples-javaconfig-rememberme.gradle delete mode 100644 samples/javaconfig/rememberme/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/rememberme/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/rememberme/src/main/resources/logback.xml delete mode 100644 samples/javaconfig/rememberme/src/main/resources/views/login.html delete mode 100644 samples/javaconfig/rememberme/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/rememberme/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/javaconfig/saml2login/spring-security-samples-javaconfig-saml2login.gradle delete mode 100644 samples/javaconfig/saml2login/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/saml2login/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/saml2login/src/main/resources/logback.xml delete mode 100644 samples/javaconfig/saml2login/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/javaconfig/x509/spring-security-samples-javaconfig-x509.gradle delete mode 100644 samples/javaconfig/x509/src/etc/ca.pem delete mode 100644 samples/javaconfig/x509/src/etc/dianne.p12 delete mode 100644 samples/javaconfig/x509/src/etc/rod.p12 delete mode 100644 samples/javaconfig/x509/src/etc/scott.p12 delete mode 100644 samples/javaconfig/x509/src/etc/server.jks delete mode 100644 samples/javaconfig/x509/src/etc/server.xml delete mode 100644 samples/javaconfig/x509/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java delete mode 100644 samples/javaconfig/x509/src/main/java/org/springframework/security/samples/config/SecurityConfig.java delete mode 100644 samples/javaconfig/x509/src/main/resources/logback.xml delete mode 100644 samples/javaconfig/x509/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/javaconfig/x509/src/main/webapp/WEB-INF/decorators.xml delete mode 100644 samples/javaconfig/x509/src/main/webapp/WEB-INF/decorators/main.jsp delete mode 100644 samples/javaconfig/x509/src/main/webapp/WEB-INF/views/login.jspx delete mode 100644 samples/javaconfig/x509/src/main/webapp/WEB-INF/views/messages/compose.jspx delete mode 100644 samples/javaconfig/x509/src/main/webapp/WEB-INF/views/messages/inbox.jspx delete mode 100644 samples/javaconfig/x509/src/main/webapp/WEB-INF/views/messages/show.jspx delete mode 100644 samples/javaconfig/x509/src/main/webapp/WEB-INF/web.xml- delete mode 100644 samples/javaconfig/x509/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/xml/aspectj/spring-security-samples-xml-aspectj.gradle delete mode 100644 samples/xml/aspectj/src/main/java/sample/aspectj/SecuredService.java delete mode 100644 samples/xml/aspectj/src/main/java/sample/aspectj/Service.java delete mode 100644 samples/xml/aspectj/src/main/resources/aspectj-context.xml delete mode 100644 samples/xml/aspectj/src/test/java/sample/aspectj/AspectJInterceptorTests.java delete mode 100644 samples/xml/aspectj/src/test/resources/logback-test.xml delete mode 100644 samples/xml/cas/Readme.txt delete mode 100644 samples/xml/cas/cassample/spring-security-samples-xml-cassample.gradle delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/CasSampleProxyTests.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/CasSampleTests.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/JettyCasService.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/pages/AccessDeniedPage.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/pages/ExtremelySecurePage.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/pages/HomePage.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/pages/LocalLogoutPage.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/pages/LoginPage.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/pages/Page.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/pages/ProxyTicketSamplePage.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/pages/SecurePage.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/java/org/springframework/security/samples/cas/pages/UnauthorizedPage.java delete mode 100644 samples/xml/cas/cassample/src/integration-test/resources/logback-test.xml delete mode 100644 samples/xml/cas/cassample/src/main/java/org/springframework/security/samples/cas/web/ProxyTicketSampleServlet.java delete mode 100644 samples/xml/cas/cassample/src/main/webapp/401.jsp delete mode 100644 samples/xml/cas/cassample/src/main/webapp/403.jsp delete mode 100644 samples/xml/cas/cassample/src/main/webapp/WEB-INF/applicationContext-security.xml delete mode 100644 samples/xml/cas/cassample/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/cas/cassample/src/main/webapp/cas-logout.jsp delete mode 100644 samples/xml/cas/cassample/src/main/webapp/casfailed.jsp delete mode 100644 samples/xml/cas/cassample/src/main/webapp/index.jsp delete mode 100644 samples/xml/cas/cassample/src/main/webapp/secure/extreme/index.jsp delete mode 100644 samples/xml/cas/cassample/src/main/webapp/secure/index.jsp delete mode 100644 samples/xml/cas/casserver/spring-security-samples-xml-casserver.gradle delete mode 100644 samples/xml/cas/casserver/src/main/webapp/WEB-INF/classes/log4j.xml delete mode 100644 samples/xml/cas/casserver/src/main/webapp/WEB-INF/deployerConfigContext.xml delete mode 100644 samples/xml/cas/casserver/src/main/webapp/WEB-INF/spring-configuration/applicationContext.xml delete mode 100644 samples/xml/cas/spring-security-samples-xml-cas.gradle delete mode 100644 samples/xml/contacts/client/client.properties delete mode 100644 samples/xml/contacts/client/clientContext.xml delete mode 100644 samples/xml/contacts/spring-security-samples-xml-contacts.gradle delete mode 100644 samples/xml/contacts/src/integration-test/java/org/springframework/security/samples/ContactsTests.java delete mode 100644 samples/xml/contacts/src/integration-test/java/org/springframework/security/samples/pages/AddPage.java delete mode 100644 samples/xml/contacts/src/integration-test/java/org/springframework/security/samples/pages/ContactsPage.java delete mode 100644 samples/xml/contacts/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java delete mode 100644 samples/xml/contacts/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/AddDeleteContactController.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/AddPermission.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/AddPermissionValidator.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/AdminPermissionController.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/ClientApplication.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/Contact.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/ContactDao.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/ContactDaoSpring.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/ContactManager.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/ContactManagerBackend.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/DataSourcePopulator.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/IndexController.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/WebContact.java delete mode 100644 samples/xml/contacts/src/main/java/sample/contact/WebContactValidator.java delete mode 100644 samples/xml/contacts/src/main/resources/applicationContext-common-authorization.xml delete mode 100644 samples/xml/contacts/src/main/resources/applicationContext-common-business.xml delete mode 100644 samples/xml/contacts/src/main/resources/applicationContext-security.xml delete mode 100644 samples/xml/contacts/src/main/resources/logback.xml delete mode 100644 samples/xml/contacts/src/main/resources/messages.properties delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/contacts-servlet.xml delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/jsp/add.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/jsp/addPermission.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/jsp/adminPermission.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/jsp/deletePermission.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/jsp/deleted.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/jsp/frames.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/jsp/hello.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/jsp/include.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/jsp/index.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/remoting-servlet.xml delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/spring.tld delete mode 100644 samples/xml/contacts/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/contacts/src/main/webapp/accessDenied.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/error.html delete mode 100644 samples/xml/contacts/src/main/webapp/exitUser.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/index.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/login.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/secure/debug.jsp delete mode 100644 samples/xml/contacts/src/main/webapp/switchUser.jsp delete mode 100644 samples/xml/contacts/src/site/resources/logback-test.xml delete mode 100644 samples/xml/contacts/src/site/resources/sslhowto.txt delete mode 100644 samples/xml/contacts/src/test/java/sample/contact/ContactManagerTests.java delete mode 100644 samples/xml/contacts/src/test/resources/logback-test.xml delete mode 100644 samples/xml/dms/spring-security-samples-xml-dms.gradle delete mode 100755 samples/xml/dms/src/main/java/sample/dms/AbstractElement.java delete mode 100755 samples/xml/dms/src/main/java/sample/dms/DataSourcePopulator.java delete mode 100755 samples/xml/dms/src/main/java/sample/dms/Directory.java delete mode 100755 samples/xml/dms/src/main/java/sample/dms/DocumentDao.java delete mode 100755 samples/xml/dms/src/main/java/sample/dms/DocumentDaoImpl.java delete mode 100755 samples/xml/dms/src/main/java/sample/dms/File.java delete mode 100755 samples/xml/dms/src/main/java/sample/dms/secured/SecureDataSourcePopulator.java delete mode 100755 samples/xml/dms/src/main/java/sample/dms/secured/SecureDocumentDao.java delete mode 100755 samples/xml/dms/src/main/java/sample/dms/secured/SecureDocumentDaoImpl.java delete mode 100755 samples/xml/dms/src/main/resources/applicationContext-dms-insecure.xml delete mode 100755 samples/xml/dms/src/main/resources/applicationContext-dms-secure.xml delete mode 100755 samples/xml/dms/src/main/resources/applicationContext-dms-shared.xml delete mode 100644 samples/xml/dms/src/test/java/sample/DmsIntegrationTests.java delete mode 100644 samples/xml/dms/src/test/java/sample/SecureDmsIntegrationTests.java delete mode 100644 samples/xml/dms/src/test/resources/logback-test.xml delete mode 100644 samples/xml/gae/README.adoc delete mode 100644 samples/xml/gae/spring-security-samples-xml-gae.gradle delete mode 100644 samples/xml/gae/src/main/java/samples/gae/security/AppRole.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/security/GaeAuthenticationFilter.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/security/GaeUserAuthentication.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/security/GoogleAccountsAuthenticationEntryPoint.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/security/GoogleAccountsAuthenticationProvider.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/users/GaeDatastoreUserRegistry.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/users/GaeUser.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/users/InMemoryUserRegistry.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/users/UserRegistry.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/validation/Forename.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/validation/ForenameValidator.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/validation/Surname.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/validation/SurnameValidator.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/web/GaeAppController.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/web/RegistrationController.java delete mode 100644 samples/xml/gae/src/main/java/samples/gae/web/RegistrationForm.java delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/appengine-web.xml delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/applicationContext-security.xml delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/classes/ValidationMessages.properties delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/gae-servlet.xml delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/jsp/disabled.jsp delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/jsp/home.jsp delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/jsp/landing.jsp delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/jsp/loggedout.jsp delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/jsp/register.jsp delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/logging.properties delete mode 100644 samples/xml/gae/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/gae/src/main/webapp/favicon.ico delete mode 100644 samples/xml/gae/src/main/webapp/static/css/gae.css delete mode 100644 samples/xml/gae/src/test/java/samples/gae/security/AppRoleTests.java delete mode 100644 samples/xml/gae/src/test/java/samples/gae/users/GaeDataStoreUserRegistryTests.java delete mode 100644 samples/xml/gae/src/test/resources/logback-test.xml delete mode 100644 samples/xml/helloworld/spring-security-samples-xml-helloworld.gradle delete mode 100644 samples/xml/helloworld/src/integration-test/java/org/springframework/security/samples/HelloWorldXmlTests.java delete mode 100644 samples/xml/helloworld/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java delete mode 100644 samples/xml/helloworld/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java delete mode 100644 samples/xml/helloworld/src/main/resources/logback.xml delete mode 100644 samples/xml/helloworld/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/xml/helloworld/src/main/webapp/WEB-INF/spring/security.xml delete mode 100644 samples/xml/helloworld/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/helloworld/src/main/webapp/index.jsp delete mode 100644 samples/xml/helloworld/src/main/webapp/resources/css/bootstrap-responsive.css delete mode 100644 samples/xml/helloworld/src/main/webapp/resources/css/bootstrap.css delete mode 100644 samples/xml/helloworld/src/main/webapp/resources/img/favicon.ico delete mode 100644 samples/xml/helloworld/src/main/webapp/resources/img/logo.png delete mode 100644 samples/xml/insecure/spring-security-samples-xml-insecure.gradle delete mode 100644 samples/xml/insecure/src/integration-test/java/org/springframework/security/samples/HelloInsecureTests.java delete mode 100644 samples/xml/insecure/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java delete mode 100644 samples/xml/insecure/src/main/java/README.adoc delete mode 100644 samples/xml/insecure/src/main/webapp/index.jsp delete mode 100644 samples/xml/insecure/src/main/webapp/resources/css/bootstrap-responsive.css delete mode 100644 samples/xml/insecure/src/main/webapp/resources/css/bootstrap.css delete mode 100644 samples/xml/insecure/src/main/webapp/resources/img/favicon.ico delete mode 100644 samples/xml/insecure/src/main/webapp/resources/img/logo.png delete mode 100644 samples/xml/insecuremvc/spring-security-samples-xml-insecuremvc.gradle delete mode 100644 samples/xml/insecuremvc/src/main/java/README.adoc delete mode 100644 samples/xml/insecuremvc/src/main/webapp/META-INF/MANIFEST.MF delete mode 100644 samples/xml/insecuremvc/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java delete mode 100644 samples/xml/insecuremvc/src/test/resources/logback-test.xml delete mode 100644 samples/xml/jaas/spring-security-samples-xml-jaas.gradle delete mode 100644 samples/xml/jaas/src/integration-test/java/org/springframework/security/samples/JaasXmlTests.java delete mode 100644 samples/xml/jaas/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java delete mode 100644 samples/xml/jaas/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java delete mode 100644 samples/xml/jaas/src/integration-test/java/org/springframework/security/samples/pages/LogoutPage.java delete mode 100644 samples/xml/jaas/src/integration-test/java/org/springframework/security/samples/pages/SecurePage.java delete mode 100644 samples/xml/jaas/src/main/java/samples/jaas/RoleUserAuthorityGranter.java delete mode 100644 samples/xml/jaas/src/main/java/samples/jaas/UsernameEqualsPasswordLoginModule.java delete mode 100644 samples/xml/jaas/src/main/resources/applicationContext-security.xml delete mode 100644 samples/xml/jaas/src/main/resources/logback.xml delete mode 100644 samples/xml/jaas/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/jaas/src/main/webapp/index.jsp delete mode 100644 samples/xml/jaas/src/main/webapp/secure/index.jsp delete mode 100644 samples/xml/ldap/spring-security-samples-xml-ldap.gradle delete mode 100644 samples/xml/ldap/src/integration-test/java/org/springframework/security/samples/LdapXmlTests.java delete mode 100644 samples/xml/ldap/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java delete mode 100644 samples/xml/ldap/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java delete mode 100644 samples/xml/ldap/src/integration-test/java/org/springframework/security/samples/pages/LogoutPage.java delete mode 100644 samples/xml/ldap/src/integration-test/java/org/springframework/security/samples/pages/SecurePage.java delete mode 100644 samples/xml/ldap/src/main/resources/logback.xml delete mode 100644 samples/xml/ldap/src/main/resources/users.ldif delete mode 100644 samples/xml/ldap/src/main/webapp/WEB-INF/applicationContext-security.xml delete mode 100644 samples/xml/ldap/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/ldap/src/main/webapp/index.jsp delete mode 100644 samples/xml/ldap/src/main/webapp/secure/extreme/index.jsp delete mode 100644 samples/xml/ldap/src/main/webapp/secure/index.jsp delete mode 100644 samples/xml/oauth2login/README.adoc delete mode 100644 samples/xml/oauth2login/spring-security-samples-xml-oauth2login.gradle delete mode 100644 samples/xml/oauth2login/src/main/java/sample/config/WebConfig.java delete mode 100644 samples/xml/oauth2login/src/main/java/sample/web/OAuth2LoginController.java delete mode 100644 samples/xml/oauth2login/src/main/webapp/WEB-INF/security.xml delete mode 100644 samples/xml/oauth2login/src/main/webapp/WEB-INF/spring-servlet.xml delete mode 100644 samples/xml/oauth2login/src/main/webapp/WEB-INF/templates/index.html delete mode 100644 samples/xml/oauth2login/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/openid/spring-security-samples-xml-openid.gradle delete mode 100644 samples/xml/openid/src/main/java/org/springframework/security/samples/openid/CustomUserDetails.java delete mode 100644 samples/xml/openid/src/main/java/org/springframework/security/samples/openid/CustomUserDetailsService.java delete mode 100644 samples/xml/openid/src/main/resources/logback.xml delete mode 100644 samples/xml/openid/src/main/webapp/WEB-INF/applicationContext-security.xml delete mode 100644 samples/xml/openid/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/openid/src/main/webapp/css/openid.css delete mode 100644 samples/xml/openid/src/main/webapp/images/aol.gif delete mode 100644 samples/xml/openid/src/main/webapp/images/blogger.ico delete mode 100644 samples/xml/openid/src/main/webapp/images/claimid.ico delete mode 100644 samples/xml/openid/src/main/webapp/images/facebook.gif delete mode 100644 samples/xml/openid/src/main/webapp/images/flickr.ico delete mode 100644 samples/xml/openid/src/main/webapp/images/google.gif delete mode 100644 samples/xml/openid/src/main/webapp/images/livejournal.ico delete mode 100644 samples/xml/openid/src/main/webapp/images/myopenid.ico delete mode 100644 samples/xml/openid/src/main/webapp/images/openid-inputicon.gif delete mode 100644 samples/xml/openid/src/main/webapp/images/openid.gif delete mode 100644 samples/xml/openid/src/main/webapp/images/technorati.ico delete mode 100644 samples/xml/openid/src/main/webapp/images/verisign.gif delete mode 100644 samples/xml/openid/src/main/webapp/images/verisign.ico delete mode 100644 samples/xml/openid/src/main/webapp/images/vidoop.ico delete mode 100644 samples/xml/openid/src/main/webapp/images/wordpress.ico delete mode 100644 samples/xml/openid/src/main/webapp/images/yahoo.gif delete mode 100644 samples/xml/openid/src/main/webapp/index.jsp delete mode 100644 samples/xml/openid/src/main/webapp/js/jquery-3.5.1.min.js delete mode 100644 samples/xml/openid/src/main/webapp/js/openid-client/jquery.query-2.1.3.js delete mode 100644 samples/xml/openid/src/main/webapp/js/openid-client/openid-client-config.js delete mode 100644 samples/xml/openid/src/main/webapp/js/openid-client/openid-client.js delete mode 100644 samples/xml/openid/src/main/webapp/js/openid-jquery.js delete mode 100644 samples/xml/openid/src/main/webapp/openidlogin.jsp delete mode 100644 samples/xml/preauth/realm.properties delete mode 100644 samples/xml/preauth/spring-security-samples-xml-preauth.gradle delete mode 100644 samples/xml/preauth/src/main/resources/logback.xml delete mode 100644 samples/xml/preauth/src/main/webapp/WEB-INF/applicationContext-security.xml delete mode 100644 samples/xml/preauth/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/preauth/src/main/webapp/index.jsp delete mode 100644 samples/xml/preauth/src/main/webapp/secure/extreme/index.jsp delete mode 100644 samples/xml/preauth/src/main/webapp/secure/index.jsp delete mode 100644 samples/xml/preauth/src/test/java/sample/PreAuthXmlTests.java delete mode 100644 samples/xml/preauth/src/test/resources/logback-test.xml delete mode 100644 samples/xml/servletapi/spring-security-samples-xml-servletapi.gradle delete mode 100644 samples/xml/servletapi/src/main/java/org/springframework/security/samples/servletapi/mvc/LoginForm.java delete mode 100644 samples/xml/servletapi/src/main/java/org/springframework/security/samples/servletapi/mvc/ServletApiController.java delete mode 100644 samples/xml/servletapi/src/main/resources/applicationContext-security.xml delete mode 100644 samples/xml/servletapi/src/main/resources/logback.xml delete mode 100644 samples/xml/servletapi/src/main/webapp/WEB-INF/spring-servlet.xml delete mode 100644 samples/xml/servletapi/src/main/webapp/WEB-INF/views/index.jsp delete mode 100644 samples/xml/servletapi/src/main/webapp/WEB-INF/views/login.jsp delete mode 100644 samples/xml/servletapi/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/tutorial/readme.txt delete mode 100755 samples/xml/tutorial/scripts/exec-list-as-peter delete mode 100755 samples/xml/tutorial/scripts/exec-list-as-rod delete mode 100755 samples/xml/tutorial/scripts/exec-list-no-auth delete mode 100755 samples/xml/tutorial/scripts/exec-list-wrong-password delete mode 100755 samples/xml/tutorial/scripts/exec-post-as-peter delete mode 100755 samples/xml/tutorial/scripts/exec-post-as-rod delete mode 100755 samples/xml/tutorial/scripts/exec-post-no-auth delete mode 100755 samples/xml/tutorial/scripts/exec-post-wrong-password delete mode 100644 samples/xml/tutorial/spring-security-samples-xml-tutorial.gradle delete mode 100644 samples/xml/tutorial/src/main/java/bigbank/Account.java delete mode 100644 samples/xml/tutorial/src/main/java/bigbank/BankDao.java delete mode 100644 samples/xml/tutorial/src/main/java/bigbank/BankDaoStub.java delete mode 100644 samples/xml/tutorial/src/main/java/bigbank/BankService.java delete mode 100644 samples/xml/tutorial/src/main/java/bigbank/BankServiceImpl.java delete mode 100644 samples/xml/tutorial/src/main/java/bigbank/SeedData.java delete mode 100644 samples/xml/tutorial/src/main/java/bigbank/web/ListAccounts.java delete mode 100644 samples/xml/tutorial/src/main/java/bigbank/web/PostAccounts.java delete mode 100644 samples/xml/tutorial/src/main/resources/applicationContext-business.xml delete mode 100644 samples/xml/tutorial/src/main/resources/logback.xml delete mode 100644 samples/xml/tutorial/src/main/webapp/WEB-INF/applicationContext-security.xml delete mode 100644 samples/xml/tutorial/src/main/webapp/WEB-INF/bank-servlet.xml delete mode 100644 samples/xml/tutorial/src/main/webapp/WEB-INF/jsp/listAccounts.jsp delete mode 100644 samples/xml/tutorial/src/main/webapp/WEB-INF/web.xml delete mode 100644 samples/xml/tutorial/src/main/webapp/index.jsp delete mode 100644 samples/xml/tutorial/src/main/webapp/loggedout.jsp delete mode 100644 samples/xml/tutorial/src/main/webapp/secure/extreme/index.jsp delete mode 100644 samples/xml/tutorial/src/main/webapp/secure/index.jsp delete mode 100644 samples/xml/tutorial/src/main/webapp/static/css/tutorial.css delete mode 100644 samples/xml/tutorial/src/main/webapp/timeout.jsp diff --git a/samples/boot/hellorsocket/spring-security-samples-boot-hellorsocket.gradle b/samples/boot/hellorsocket/spring-security-samples-boot-hellorsocket.gradle deleted file mode 100644 index f2b788a0e2..0000000000 --- a/samples/boot/hellorsocket/spring-security-samples-boot-hellorsocket.gradle +++ /dev/null @@ -1,11 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-core') - compile project(':spring-security-config') - compile project(':spring-security-rsocket') - compile 'org.springframework.boot:spring-boot-starter-rsocket' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/hellorsocket/src/integration-test/java/sample/HelloRSocketApplicationITests.java b/samples/boot/hellorsocket/src/integration-test/java/sample/HelloRSocketApplicationITests.java deleted file mode 100644 index 0709dd93bc..0000000000 --- a/samples/boot/hellorsocket/src/integration-test/java/sample/HelloRSocketApplicationITests.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.rsocket.context.LocalRSocketServerPort; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.messaging.rsocket.RSocketRequester; -import org.springframework.security.rsocket.metadata.BasicAuthenticationEncoder; -import org.springframework.security.rsocket.metadata.UsernamePasswordMetadata; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; - -import org.junit.Test; -import org.junit.runner.RunWith; -import reactor.core.publisher.Mono; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.springframework.security.rsocket.metadata.UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE; - -/** - * @author Rob Winch - * @author Eddú Meléndez - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@TestPropertySource(properties = "spring.rsocket.server.port=0") -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class HelloRSocketApplicationITests { - - @Autowired - RSocketRequester.Builder requester; - - @LocalRSocketServerPort - int port; - - @Test - public void messageWhenAuthenticatedThenSuccess() { - UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password"); - RSocketRequester requester = this.requester - .rsocketStrategies((builder) -> builder.encoder(new BasicAuthenticationEncoder())) - .setupMetadata(credentials, BASIC_AUTHENTICATION_MIME_TYPE) - .connectTcp("localhost", this.port) - .block(); - - String message = requester.route("message") - .data(Mono.empty()) - .retrieveMono(String.class) - .block(); - - assertThat(message).isEqualTo("Hello"); - } - - @Test - public void messageWhenNotAuthenticatedThenError() { - RSocketRequester requester = this.requester - .connectTcp("localhost", this.port) - .block(); - - assertThatThrownBy(() -> requester.route("message") - .data(Mono.empty()) - .retrieveMono(String.class) - .block()) - .isNotNull(); - } - -} diff --git a/samples/boot/hellorsocket/src/main/java/sample/HelloRSocketApplication.java b/samples/boot/hellorsocket/src/main/java/sample/HelloRSocketApplication.java deleted file mode 100644 index fbbc6df27d..0000000000 --- a/samples/boot/hellorsocket/src/main/java/sample/HelloRSocketApplication.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Rob Winch - * @since 5.2 - */ -@SpringBootApplication -public class HelloRSocketApplication { - - public static void main(String[] args) { - SpringApplication.run(HelloRSocketApplication.class, args); - } - -} diff --git a/samples/boot/hellorsocket/src/main/java/sample/HelloRSocketSecurityConfig.java b/samples/boot/hellorsocket/src/main/java/sample/HelloRSocketSecurityConfig.java deleted file mode 100644 index 9f469f08e7..0000000000 --- a/samples/boot/hellorsocket/src/main/java/sample/HelloRSocketSecurityConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.rsocket.EnableRSocketSecurity; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; - -/** - * @author Rob Winch - * @since 5.2 - */ -@Configuration -@EnableRSocketSecurity -public class HelloRSocketSecurityConfig { - - @Bean - MapReactiveUserDetailsService userDetailsService() { - UserDetails user = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("SETUP") - .build(); - return new MapReactiveUserDetailsService(user); - } - -} diff --git a/samples/boot/hellorsocket/src/main/java/sample/MessageController.java b/samples/boot/hellorsocket/src/main/java/sample/MessageController.java deleted file mode 100644 index 0150b3f821..0000000000 --- a/samples/boot/hellorsocket/src/main/java/sample/MessageController.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.stereotype.Controller; -import reactor.core.publisher.Mono; - -/** - * @author Rob Winch - * @since 5.2 - */ -@Controller -public class MessageController { - - @MessageMapping("message") - public Mono message() { - return Mono.just("Hello"); - } -} diff --git a/samples/boot/hellorsocket/src/main/resources/application.properties b/samples/boot/hellorsocket/src/main/resources/application.properties deleted file mode 100644 index 0d91b628f6..0000000000 --- a/samples/boot/hellorsocket/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -spring.rsocket.server.port=8080 diff --git a/samples/boot/hellowebflux-method/spring-security-samples-boot-hellowebflux-method.gradle b/samples/boot/hellowebflux-method/spring-security-samples-boot-hellowebflux-method.gradle deleted file mode 100644 index c21781806f..0000000000 --- a/samples/boot/hellowebflux-method/spring-security-samples-boot-hellowebflux-method.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-core') - compile project(':spring-security-config') - compile project(':spring-security-web') - compile 'org.springframework.boot:spring-boot-starter-webflux' - - testCompile project(':spring-security-test') - testCompile 'io.projectreactor:reactor-test' - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/hellowebflux-method/src/integration-test/java/sample/HelloWebfluxMethodApplicationITests.java b/samples/boot/hellowebflux-method/src/integration-test/java/sample/HelloWebfluxMethodApplicationITests.java deleted file mode 100644 index d95956b2d6..0000000000 --- a/samples/boot/hellowebflux-method/src/integration-test/java/sample/HelloWebfluxMethodApplicationITests.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.util.function.Consumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class HelloWebfluxMethodApplicationITests { - - @Autowired - WebTestClient rest; - - - @Test - public void messageWhenNotAuthenticated() { - this.rest - .get() - .uri("/message") - .exchange() - .expectStatus().isUnauthorized(); - } - - @Test - public void messageWhenUserThenForbidden() { - this.rest - .get() - .uri("/message") - .headers(robsCredentials()) - .exchange() - .expectStatus().isEqualTo(HttpStatus.FORBIDDEN); - } - - @Test - public void messageWhenAdminThenOk() { - this.rest - .get() - .uri("/message") - .headers(adminCredentials()) - .exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("Hello World!"); - } - - private Consumer robsCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("rob", "rob"); - } - - private Consumer adminCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("admin", "admin"); - } -} - diff --git a/samples/boot/hellowebflux-method/src/main/java/sample/HelloWebfluxMethodApplication.java b/samples/boot/hellowebflux-method/src/main/java/sample/HelloWebfluxMethodApplication.java deleted file mode 100644 index 37aec1d99f..0000000000 --- a/samples/boot/hellowebflux-method/src/main/java/sample/HelloWebfluxMethodApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Rob Winch - * @since 5.0 - */ -@SpringBootApplication -public class HelloWebfluxMethodApplication { - - public static void main(String[] args) { - SpringApplication.run(HelloWebfluxMethodApplication.class, args); - } -} diff --git a/samples/boot/hellowebflux-method/src/main/java/sample/HelloWorldMessageService.java b/samples/boot/hellowebflux-method/src/main/java/sample/HelloWorldMessageService.java deleted file mode 100644 index c6184c830d..0000000000 --- a/samples/boot/hellowebflux-method/src/main/java/sample/HelloWorldMessageService.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Mono; - -/** - * @author Rob Winch - * @since 5.0 - */ -@Component -public class HelloWorldMessageService { - @PreAuthorize("hasRole('ADMIN')") - public Mono findMessage() { - return Mono.just("Hello World!"); - } -} diff --git a/samples/boot/hellowebflux-method/src/main/java/sample/MessageController.java b/samples/boot/hellowebflux-method/src/main/java/sample/MessageController.java deleted file mode 100644 index b8e96e6a45..0000000000 --- a/samples/boot/hellowebflux-method/src/main/java/sample/MessageController.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Mono; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RestController -public class MessageController { - private final HelloWorldMessageService messages; - - public MessageController(HelloWorldMessageService messages) { - this.messages = messages; - } - - @GetMapping("/message") - public Mono message() { - return this.messages.findMessage(); - } -} diff --git a/samples/boot/hellowebflux-method/src/main/java/sample/SecurityConfig.java b/samples/boot/hellowebflux-method/src/main/java/sample/SecurityConfig.java deleted file mode 100644 index fbbcdc835e..0000000000 --- a/samples/boot/hellowebflux-method/src/main/java/sample/SecurityConfig.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.web.server.SecurityWebFilterChain; - -import static org.springframework.security.config.Customizer.withDefaults; - -/** - * @author Rob Winch - * @since 5.0 - */ -@EnableWebFluxSecurity -@EnableReactiveMethodSecurity -public class SecurityConfig { - - @Bean - SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) { - return http - // Demonstrate that method security works - // Best practice to use both for defense in depth - .authorizeExchange((exchanges) -> exchanges - .anyExchange().permitAll() - ) - .httpBasic(withDefaults()) - .build(); - } - - @Bean - public MapReactiveUserDetailsService userDetailsService() { - User.UserBuilder userBuilder = User.withDefaultPasswordEncoder(); - UserDetails rob = userBuilder.username("rob").password("rob").roles("USER").build(); - UserDetails admin = userBuilder.username("admin").password("admin").roles("USER", "ADMIN").build(); - return new MapReactiveUserDetailsService(rob, admin); - } - -} diff --git a/samples/boot/hellowebflux-method/src/test/java/sample/HelloWebfluxMethodApplicationTests.java b/samples/boot/hellowebflux-method/src/test/java/sample/HelloWebfluxMethodApplicationTests.java deleted file mode 100644 index 6a2e2898ed..0000000000 --- a/samples/boot/hellowebflux-method/src/test/java/sample/HelloWebfluxMethodApplicationTests.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockUser; -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity; - -import java.util.function.Consumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@SpringBootTest -public class HelloWebfluxMethodApplicationTests { - WebTestClient rest; - - @Autowired - public void setup(ApplicationContext context) { - this.rest = WebTestClient - .bindToApplicationContext(context) - .apply(springSecurity()) - .configureClient() - .build(); - } - - @Test - public void messageWhenNotAuthenticated() { - this.rest - .get() - .uri("/message") - .exchange() - .expectStatus().isUnauthorized(); - } - - @Test - public void messageWhenUserThenForbidden() { - this.rest - .get() - .uri("/message") - .headers(robsCredentials()) - .exchange() - .expectStatus().isEqualTo(HttpStatus.FORBIDDEN); - } - - @Test - public void messageWhenAdminThenOk() { - this.rest - .get() - .uri("/message") - .headers(adminCredentials()) - .exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("Hello World!"); - } - - @Test - @WithMockUser - public void messageWhenWithMockUserThenForbidden() { - this.rest - .get() - .uri("/message") - .exchange() - .expectStatus().isEqualTo(HttpStatus.FORBIDDEN); - } - - @Test - @WithMockUser(roles = "ADMIN") - public void messageWhenWithMockAdminThenOk() { - this.rest - .get() - .uri("/message") - .exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("Hello World!"); - } - - @Test - public void messageWhenMutateWithMockUserThenForbidden() { - this.rest - .mutateWith(mockUser()) - .get() - .uri("/message") - .exchange() - .expectStatus().isEqualTo(HttpStatus.FORBIDDEN); - } - - @Test - public void messageWhenMutateWithMockAdminThenOk() { - this.rest - .mutateWith(mockUser().roles("ADMIN")) - .get() - .uri("/message") - .exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("Hello World!"); - } - - private Consumer robsCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("rob", "rob"); - } - - private Consumer adminCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("admin", "admin"); - } -} diff --git a/samples/boot/hellowebflux-method/src/test/java/sample/HelloWorldMessageServiceTests.java b/samples/boot/hellowebflux-method/src/test/java/sample/HelloWorldMessageServiceTests.java deleted file mode 100644 index d8f2aae925..0000000000 --- a/samples/boot/hellowebflux-method/src/test/java/sample/HelloWorldMessageServiceTests.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit4.SpringRunner; -import reactor.test.StepVerifier; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@SpringBootTest -public class HelloWorldMessageServiceTests { - @Autowired - HelloWorldMessageService messages; - - @Test - public void messagesWhenNotAuthenticatedThenDenied() { - StepVerifier.create(this.messages.findMessage()) - .expectError(AccessDeniedException.class) - .verify(); - } - - @Test - @WithMockUser - public void messagesWhenUserThenDenied() { - StepVerifier.create(this.messages.findMessage()) - .expectError(AccessDeniedException.class) - .verify(); - } - - @Test - @WithMockUser(roles = "ADMIN") - public void messagesWhenAdminThenOk() { - StepVerifier.create(this.messages.findMessage()) - .expectNext("Hello World!") - .verifyComplete(); - } -} diff --git a/samples/boot/hellowebflux/spring-security-samples-boot-hellowebflux.gradle b/samples/boot/hellowebflux/spring-security-samples-boot-hellowebflux.gradle deleted file mode 100644 index d65d168ad1..0000000000 --- a/samples/boot/hellowebflux/spring-security-samples-boot-hellowebflux.gradle +++ /dev/null @@ -1,11 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-core') - compile project(':spring-security-config') - compile project(':spring-security-web') - compile 'org.springframework.boot:spring-boot-starter-webflux' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/hellowebflux/src/integration-test/java/sample/HelloWebfluxApplicationITests.java b/samples/boot/hellowebflux/src/integration-test/java/sample/HelloWebfluxApplicationITests.java deleted file mode 100644 index 6d1dda2fac..0000000000 --- a/samples/boot/hellowebflux/src/integration-test/java/sample/HelloWebfluxApplicationITests.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.util.function.Consumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class HelloWebfluxApplicationITests { - - @Autowired - WebTestClient rest; - - @Test - public void basicWhenNoCredentialsThenUnauthorized() { - this.rest - .get() - .uri("/") - .exchange() - .expectStatus().isUnauthorized(); - } - - @Test - public void basicWhenValidCredentialsThenOk() { - this.rest - .get() - .uri("/") - .headers(userCredentials()) - .exchange() - .expectStatus().isOk() - .expectBody().json("{\"message\":\"Hello user!\"}"); - } - - @Test - public void basicWhenInvalidCredentialsThenUnauthorized() { - this.rest - .get() - .uri("/") - .headers(invalidCredentials()) - .exchange() - .expectStatus().isUnauthorized() - .expectBody().isEmpty(); - } - - private Consumer userCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("user", "user"); - } - - private Consumer invalidCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("user", "INVALID"); - } -} diff --git a/samples/boot/hellowebflux/src/main/java/sample/HelloUserController.java b/samples/boot/hellowebflux/src/main/java/sample/HelloUserController.java deleted file mode 100644 index e06932f222..0000000000 --- a/samples/boot/hellowebflux/src/main/java/sample/HelloUserController.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.security.Principal; -import java.util.Collections; -import java.util.Map; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Mono; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RestController -public class HelloUserController { - - @GetMapping("/") - public Mono> hello(Mono principal) { - return principal - .map(Principal::getName) - .map(this::helloMessage); - } - - private Map helloMessage(String username) { - return Collections.singletonMap("message", "Hello " + username + "!"); - } -} diff --git a/samples/boot/hellowebflux/src/main/java/sample/HelloWebfluxApplication.java b/samples/boot/hellowebflux/src/main/java/sample/HelloWebfluxApplication.java deleted file mode 100644 index b3b27fdf73..0000000000 --- a/samples/boot/hellowebflux/src/main/java/sample/HelloWebfluxApplication.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Rob Winch - * @since 5.0 - */ -@SpringBootApplication -public class HelloWebfluxApplication { - - public static void main(String[] args) { - SpringApplication.run(HelloWebfluxApplication.class, args); - } - -} diff --git a/samples/boot/hellowebflux/src/main/java/sample/HelloWebfluxSecurityConfig.java b/samples/boot/hellowebflux/src/main/java/sample/HelloWebfluxSecurityConfig.java deleted file mode 100644 index e082133afd..0000000000 --- a/samples/boot/hellowebflux/src/main/java/sample/HelloWebfluxSecurityConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; - -/** - * @author Rob Winch - * @since 5.0 - */ -@EnableWebFluxSecurity -public class HelloWebfluxSecurityConfig { - - @Bean - public MapReactiveUserDetailsService userDetailsService() { - UserDetails user = User.withDefaultPasswordEncoder() - .username("user") - .password("user") - .roles("USER") - .build(); - return new MapReactiveUserDetailsService(user); - } -} diff --git a/samples/boot/hellowebflux/src/test/java/sample/HelloWebfluxApplicationTests.java b/samples/boot/hellowebflux/src/test/java/sample/HelloWebfluxApplicationTests.java deleted file mode 100644 index cc7892116f..0000000000 --- a/samples/boot/hellowebflux/src/test/java/sample/HelloWebfluxApplicationTests.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockUser; -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity; - -import java.util.function.Consumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; -import org.springframework.http.HttpHeaders; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureWebTestClient -public class HelloWebfluxApplicationTests { - WebTestClient rest; - - @Autowired - public void setup(ApplicationContext context) { - this.rest = WebTestClient - .bindToApplicationContext(context) - .apply(springSecurity()) - .configureClient() - .build(); - } - - @Test - public void basicWhenNoCredentialsThenUnauthorized() { - this.rest - .get() - .uri("/") - .exchange() - .expectStatus().isUnauthorized(); - } - - @Test - public void basicWhenValidCredentialsThenOk() { - this.rest - .get() - .uri("/") - .headers(userCredentials()) - .exchange() - .expectStatus().isOk() - .expectBody().json("{\"message\":\"Hello user!\"}"); - } - - @Test - public void basicWhenInvalidCredentialsThenUnauthorized() { - this.rest - .get() - .uri("/") - .headers(invalidCredentials()) - .exchange() - .expectStatus().isUnauthorized() - .expectBody().isEmpty(); - } - - @Test - public void mockSupportWhenMutateWithMockUserThenOk() { - this.rest - .mutateWith(mockUser()) - .get() - .uri("/") - .exchange() - .expectStatus().isOk() - .expectBody().json("{\"message\":\"Hello user!\"}"); - } - - @Test - @WithMockUser - public void mockSupportWhenWithMockUserThenOk() { - this.rest - .get() - .uri("/") - .exchange() - .expectStatus().isOk() - .expectBody().json("{\"message\":\"Hello user!\"}"); - } - - private Consumer userCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("user", "user"); - } - - private Consumer invalidCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("user", "INVALID"); - } -} diff --git a/samples/boot/hellowebfluxfn/spring-security-samples-boot-hellowebfluxfn.gradle b/samples/boot/hellowebfluxfn/spring-security-samples-boot-hellowebfluxfn.gradle deleted file mode 100644 index d65d168ad1..0000000000 --- a/samples/boot/hellowebfluxfn/spring-security-samples-boot-hellowebfluxfn.gradle +++ /dev/null @@ -1,11 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-core') - compile project(':spring-security-config') - compile project(':spring-security-web') - compile 'org.springframework.boot:spring-boot-starter-webflux' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/hellowebfluxfn/src/integration-test/java/sample/HelloWebfluxFnApplicationITests.java b/samples/boot/hellowebfluxfn/src/integration-test/java/sample/HelloWebfluxFnApplicationITests.java deleted file mode 100644 index de42538a78..0000000000 --- a/samples/boot/hellowebfluxfn/src/integration-test/java/sample/HelloWebfluxFnApplicationITests.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.util.function.Consumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.web.reactive.function.client.ExchangeFilterFunctions; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class HelloWebfluxFnApplicationITests { - - WebTestClient rest; - - @Autowired - public void setRest(WebTestClient rest) { - this.rest = rest - .mutateWith((b, h, c) -> b.filter(ExchangeFilterFunctions.basicAuthentication())); - } - - @Test - public void basicWhenNoCredentialsThenUnauthorized() { - this.rest - .get() - .uri("/") - .exchange() - .expectStatus().isUnauthorized(); - } - - @Test - public void basicWhenValidCredentialsThenOk() { - this.rest - .get() - .uri("/") - .headers(userCredentials()) - .exchange() - .expectStatus().isOk() - .expectBody().json("{\"message\":\"Hello user!\"}"); - } - - @Test - public void basicWhenInvalidCredentialsThenUnauthorized() { - this.rest - .get() - .uri("/") - .headers(invalidCredentials()) - .exchange() - .expectStatus().isUnauthorized() - .expectBody().isEmpty(); - } - - private Consumer userCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("user", "user"); - } - - private Consumer invalidCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("user", "INVALID"); - } -} diff --git a/samples/boot/hellowebfluxfn/src/main/java/sample/HelloUserController.java b/samples/boot/hellowebfluxfn/src/main/java/sample/HelloUserController.java deleted file mode 100644 index e0c0810cee..0000000000 --- a/samples/boot/hellowebfluxfn/src/main/java/sample/HelloUserController.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.security.Principal; -import java.util.Collections; - -import reactor.core.publisher.Mono; - -import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.server.ServerRequest; -import org.springframework.web.reactive.function.server.ServerResponse; - -/** - * @author Rob Winch - * @since 5.0 - */ -@Component -public class HelloUserController { - - public Mono hello(ServerRequest serverRequest) { - return serverRequest.principal() - .map(Principal::getName) - .flatMap((username) -> - ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) - .syncBody(Collections.singletonMap("message", "Hello " + username + "!")) - ); - } -} diff --git a/samples/boot/hellowebfluxfn/src/main/java/sample/HelloWebfluxFnApplication.java b/samples/boot/hellowebfluxfn/src/main/java/sample/HelloWebfluxFnApplication.java deleted file mode 100644 index c508e9f554..0000000000 --- a/samples/boot/hellowebfluxfn/src/main/java/sample/HelloWebfluxFnApplication.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import static org.springframework.web.reactive.function.server.RequestPredicates.GET; -import static org.springframework.web.reactive.function.server.RouterFunctions.route; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; -import org.springframework.web.reactive.function.server.RouterFunction; -import org.springframework.web.reactive.function.server.ServerResponse; - -/** - * @author Rob Winch - * @since 5.0 - */ -@SpringBootApplication -public class HelloWebfluxFnApplication { - - public static void main(String[] args) { - SpringApplication.run(HelloWebfluxFnApplication.class, args); - } - - @Bean - public RouterFunction routes(HelloUserController userController) { - return route( - GET("/"), userController::hello); - } -} diff --git a/samples/boot/hellowebfluxfn/src/main/java/sample/HelloWebfluxFnSecurityConfig.java b/samples/boot/hellowebfluxfn/src/main/java/sample/HelloWebfluxFnSecurityConfig.java deleted file mode 100644 index bd8c83c553..0000000000 --- a/samples/boot/hellowebfluxfn/src/main/java/sample/HelloWebfluxFnSecurityConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; - -/** - * @author Rob Winch - * @since 5.0 - */ -@EnableWebFluxSecurity -public class HelloWebfluxFnSecurityConfig { - - @Bean - public MapReactiveUserDetailsService userDetailsService() { - UserDetails user = User.withDefaultPasswordEncoder() - .username("user") - .password("user") - .roles("USER") - .build(); - return new MapReactiveUserDetailsService(user); - } -} diff --git a/samples/boot/hellowebfluxfn/src/test/java/sample/HelloWebfluxFnApplicationTests.java b/samples/boot/hellowebfluxfn/src/test/java/sample/HelloWebfluxFnApplicationTests.java deleted file mode 100644 index 826fe95cf3..0000000000 --- a/samples/boot/hellowebfluxfn/src/test/java/sample/HelloWebfluxFnApplicationTests.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockUser; -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity; - -import java.util.function.Consumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; -import org.springframework.http.HttpHeaders; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureWebTestClient -public class HelloWebfluxFnApplicationTests { - - WebTestClient rest; - - @Autowired - public void setup(ApplicationContext context) { - this.rest = WebTestClient - .bindToApplicationContext(context) - .apply(springSecurity()) - .configureClient() - .build(); - } - - @Test - public void basicWhenNoCredentialsThenUnauthorized() { - this.rest - .get() - .uri("/") - .exchange() - .expectStatus().isUnauthorized(); - } - - @Test - public void basicWhenValidCredentialsThenOk() { - this.rest - .get() - .uri("/") - .headers(userCredentials()) - .exchange() - .expectStatus().isOk() - .expectBody().json("{\"message\":\"Hello user!\"}"); - } - - @Test - public void basicWhenInvalidCredentialsThenUnauthorized() { - this.rest - .get() - .uri("/") - .headers(invalidCredentials()) - .exchange() - .expectStatus().isUnauthorized() - .expectBody().isEmpty(); - } - - @Test - public void mockSupportWhenMutateWithMockUserThenOk() { - this.rest - .mutateWith(mockUser()) - .get() - .uri("/") - .exchange() - .expectStatus().isOk() - .expectBody().json("{\"message\":\"Hello user!\"}"); - } - - @Test - @WithMockUser - public void mockSupportWhenWithMockUserThenOk() { - this.rest - .get() - .uri("/") - .exchange() - .expectStatus().isOk() - .expectBody().json("{\"message\":\"Hello user!\"}"); - } - - private Consumer userCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("user", "user"); - } - - private Consumer invalidCredentials() { - return (httpHeaders) -> httpHeaders.setBasicAuth("user", "INVALID"); - } -} diff --git a/samples/boot/helloworld/spring-security-samples-boot-helloworld.gradle b/samples/boot/helloworld/spring-security-samples-boot-helloworld.gradle deleted file mode 100644 index a64426286b..0000000000 --- a/samples/boot/helloworld/spring-security-samples-boot-helloworld.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-web') - compile 'org.springframework.boot:spring-boot-starter-thymeleaf' - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/helloworld/src/integration-test/java/org/springframework/security/samples/HelloWorldApplicationTests.java b/samples/boot/helloworld/src/integration-test/java/org/springframework/security/samples/HelloWorldApplicationTests.java deleted file mode 100644 index faeeb015a2..0000000000 --- a/samples/boot/helloworld/src/integration-test/java/org/springframework/security/samples/HelloWorldApplicationTests.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.mock.web.MockHttpSession; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; -import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; -import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * - * @author Joe Grandja - */ -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -public class HelloWorldApplicationTests { - - @Autowired - private MockMvc mockMvc; - - @Test - public void accessUnprotected() throws Exception { - // @formatter:off - this.mockMvc.perform(get("/index")) - .andExpect(status().isOk()); - // @formatter:on - } - - @Test - public void accessProtectedRedirectsToLogin() throws Exception { - // @formatter:off - MvcResult mvcResult = this.mockMvc.perform(get("/user/index")) - .andExpect(status().is3xxRedirection()) - .andReturn(); - // @formatter:on - - assertThat(mvcResult.getResponse().getRedirectedUrl()).endsWith("/login"); - } - - @Test - public void loginUser() throws Exception { - // @formatter:off - this.mockMvc.perform(formLogin().user("user").password("password")) - .andExpect(authenticated()); - // @formatter:on - } - - @Test - public void loginInvalidUser() throws Exception { - // @formatter:off - this.mockMvc.perform(formLogin().user("invalid").password("invalid")) - .andExpect(unauthenticated()) - .andExpect(status().is3xxRedirection()); - // @formatter:on - } - - @Test - public void loginUserAccessProtected() throws Exception { - // @formatter:off - MvcResult mvcResult = this.mockMvc.perform(formLogin().user("user").password("password")) - .andExpect(authenticated()).andReturn(); - // @formatter:on - - MockHttpSession httpSession = (MockHttpSession) mvcResult.getRequest().getSession(false); - - // @formatter:off - this.mockMvc.perform(get("/user/index").session(httpSession)) - .andExpect(status().isOk()); - // @formatter:on - } - - @Test - public void loginUserValidateLogout() throws Exception { - // @formatter:off - MvcResult mvcResult = this.mockMvc.perform(formLogin().user("user").password("password")) - .andExpect(authenticated()).andReturn(); - // @formatter:on - - MockHttpSession httpSession = (MockHttpSession) mvcResult.getRequest().getSession(false); - - // @formatter:off - this.mockMvc.perform(post("/logout").with(csrf()).session(httpSession)) - .andExpect(unauthenticated()); - this.mockMvc.perform(get("/user/index").session(httpSession)) - .andExpect(unauthenticated()) - .andExpect(status().is3xxRedirection()); - // @formatter:on - } -} diff --git a/samples/boot/helloworld/src/main/java/org/springframework/security/samples/HelloWorldApplication.java b/samples/boot/helloworld/src/main/java/org/springframework/security/samples/HelloWorldApplication.java deleted file mode 100644 index 170bcadef3..0000000000 --- a/samples/boot/helloworld/src/main/java/org/springframework/security/samples/HelloWorldApplication.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Joe Grandja - */ -@SpringBootApplication -public class HelloWorldApplication { - - public static void main(String[] args) { - SpringApplication.run(HelloWorldApplication.class, args); - } - - -} \ No newline at end of file diff --git a/samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java deleted file mode 100644 index c3c71cf2fe..0000000000 --- a/samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; - -/** - * @author Joe Grandja - */ -@EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - // @formatter:off - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests((authorize) -> authorize - .antMatchers("/css/**", "/index").permitAll() - .antMatchers("/user/**").hasRole("USER") - ) - .formLogin((formLogin) -> formLogin - .loginPage("/login") - .failureUrl("/login-error") - ); - } - // @formatter:on - - @Bean - public UserDetailsService userDetailsService() { - UserDetails userDetails = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("USER") - .build(); - return new InMemoryUserDetailsManager(userDetails); - } -} diff --git a/samples/boot/helloworld/src/main/java/org/springframework/security/samples/web/MainController.java b/samples/boot/helloworld/src/main/java/org/springframework/security/samples/web/MainController.java deleted file mode 100644 index 793a8e97eb..0000000000 --- a/samples/boot/helloworld/src/main/java/org/springframework/security/samples/web/MainController.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.web; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - * @author Joe Grandja - */ -@Controller -public class MainController { - - @RequestMapping("/") - public String root() { - return "redirect:/index"; - } - - @RequestMapping("/index") - public String index() { - return "index"; - } - - @RequestMapping("/user/index") - public String userIndex() { - return "user/index"; - } - - @RequestMapping("/login") - public String login() { - return "login"; - } - - @RequestMapping("/login-error") - public String loginError(Model model) { - model.addAttribute("loginError", true); - return "login"; - } - -} diff --git a/samples/boot/helloworld/src/main/resources/application.yml b/samples/boot/helloworld/src/main/resources/application.yml deleted file mode 100644 index b59d86df49..0000000000 --- a/samples/boot/helloworld/src/main/resources/application.yml +++ /dev/null @@ -1,12 +0,0 @@ -server: - port: 8080 - -logging: - level: - root: WARN - org.springframework.web: INFO - org.springframework.security: INFO - -spring: - thymeleaf: - cache: false diff --git a/samples/boot/helloworld/src/main/resources/static/css/main.css b/samples/boot/helloworld/src/main/resources/static/css/main.css deleted file mode 100644 index 5e6687a387..0000000000 --- a/samples/boot/helloworld/src/main/resources/static/css/main.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - font-family: sans; - font-size: 1em; -} - -p.error { - font-weight: bold; - color: red; -} - -div.logout { - float: right; -} \ No newline at end of file diff --git a/samples/boot/helloworld/src/main/resources/templates/index.html b/samples/boot/helloworld/src/main/resources/templates/index.html deleted file mode 100644 index 05fad12033..0000000000 --- a/samples/boot/helloworld/src/main/resources/templates/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - Hello Spring Security - - - - -
- Logged in user: | - Roles: -
-
- -
-
-
-

Hello Spring Security

-

This is an unsecured page, but you can access the secured pages after authenticating.

- - - diff --git a/samples/boot/helloworld/src/main/resources/templates/login.html b/samples/boot/helloworld/src/main/resources/templates/login.html deleted file mode 100644 index cec2b5b0da..0000000000 --- a/samples/boot/helloworld/src/main/resources/templates/login.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - Login page - - - - -

Login page

-

Example user: user / password

-

Wrong user or password

-
- : -
- : -
- -
-

Back to home page

- - diff --git a/samples/boot/helloworld/src/main/resources/templates/user/index.html b/samples/boot/helloworld/src/main/resources/templates/user/index.html deleted file mode 100644 index 53dd9319a5..0000000000 --- a/samples/boot/helloworld/src/main/resources/templates/user/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - Hello Spring Security - - - - -
-

This is a secured page!

-

Back to home page

- - diff --git a/samples/boot/insecure/spring-security-samples-boot-insecure.gradle b/samples/boot/insecure/spring-security-samples-boot-insecure.gradle deleted file mode 100644 index 556ebbb053..0000000000 --- a/samples/boot/insecure/spring-security-samples-boot-insecure.gradle +++ /dev/null @@ -1,8 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile 'org.springframework.boot:spring-boot-starter-thymeleaf' - compile 'org.springframework.boot:spring-boot-starter-web' - - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/insecure/src/integration-test/java/org/springframework/security/samples/InsecureApplicationTests.java b/samples/boot/insecure/src/integration-test/java/org/springframework/security/samples/InsecureApplicationTests.java deleted file mode 100644 index f2c7542e5b..0000000000 --- a/samples/boot/insecure/src/integration-test/java/org/springframework/security/samples/InsecureApplicationTests.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * - * @author Joe Grandja - */ -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -public class InsecureApplicationTests { - - @Autowired - private MockMvc mockMvc; - - @Test - public void accessUnprotected() throws Exception { - this.mockMvc.perform(get("/index")).andExpect(status().isOk()); - } - -} diff --git a/samples/boot/insecure/src/main/java/org/springframework/security/samples/InsecureApplication.java b/samples/boot/insecure/src/main/java/org/springframework/security/samples/InsecureApplication.java deleted file mode 100644 index aab24fa9d3..0000000000 --- a/samples/boot/insecure/src/main/java/org/springframework/security/samples/InsecureApplication.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Joe Grandja - */ -@SpringBootApplication -public class InsecureApplication { - - public static void main(String[] args) { - SpringApplication.run(InsecureApplication.class, args); - } - - -} diff --git a/samples/boot/insecure/src/main/java/org/springframework/security/samples/web/MainController.java b/samples/boot/insecure/src/main/java/org/springframework/security/samples/web/MainController.java deleted file mode 100644 index f7de44adcc..0000000000 --- a/samples/boot/insecure/src/main/java/org/springframework/security/samples/web/MainController.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.web; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -/** - * @author Joe Grandja - */ -@Controller -public class MainController { - - @RequestMapping("/") - public String root() { - return "redirect:/index"; - } - - @RequestMapping("/index") - public String index() { - return "index"; - } - - @RequestMapping("/user/index") - public String userIndex() { - return "user/index"; - } - - @RequestMapping(value = "/login") - public String login() { - return "login"; - } - - @RequestMapping(value = "/login", method = RequestMethod.POST) - public String postLogin() { - // TODO Enable form login with Spring Security (trigger error for now) - return "redirect:/login-error"; - } - - @RequestMapping("/login-error") - public String loginError(Model model) { - model.addAttribute("loginError", true); - return "login"; - } - -} diff --git a/samples/boot/insecure/src/main/resources/application.yml b/samples/boot/insecure/src/main/resources/application.yml deleted file mode 100644 index 0254088803..0000000000 --- a/samples/boot/insecure/src/main/resources/application.yml +++ /dev/null @@ -1,11 +0,0 @@ -server: - port: 8080 - -logging: - level: - root: WARN - org.springframework.web: INFO - -spring: - thymeleaf: - cache: false diff --git a/samples/boot/insecure/src/main/resources/static/css/main.css b/samples/boot/insecure/src/main/resources/static/css/main.css deleted file mode 100644 index 5e6687a387..0000000000 --- a/samples/boot/insecure/src/main/resources/static/css/main.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - font-family: sans; - font-size: 1em; -} - -p.error { - font-weight: bold; - color: red; -} - -div.logout { - float: right; -} \ No newline at end of file diff --git a/samples/boot/insecure/src/main/resources/templates/index.html b/samples/boot/insecure/src/main/resources/templates/index.html deleted file mode 100644 index ee9ccec618..0000000000 --- a/samples/boot/insecure/src/main/resources/templates/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - Hello Spring Security - - - - -

Hello Spring Security

-

This is an unsecured page, but you can access the secured pages after authenticating.

- - - diff --git a/samples/boot/insecure/src/main/resources/templates/login.html b/samples/boot/insecure/src/main/resources/templates/login.html deleted file mode 100644 index cec2b5b0da..0000000000 --- a/samples/boot/insecure/src/main/resources/templates/login.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - Login page - - - - -

Login page

-

Example user: user / password

-

Wrong user or password

-
- : -
- : -
- -
-

Back to home page

- - diff --git a/samples/boot/insecure/src/main/resources/templates/user/index.html b/samples/boot/insecure/src/main/resources/templates/user/index.html deleted file mode 100644 index 3fd4ccc1a3..0000000000 --- a/samples/boot/insecure/src/main/resources/templates/user/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - Hello Spring Security - - - - -

TODO Secure this

-

We would like to secure this page

-

Back to home page

- - diff --git a/samples/boot/kotlin-webflux/spring-security-samples-boot-kotlin-webflux.gradle.kts b/samples/boot/kotlin-webflux/spring-security-samples-boot-kotlin-webflux.gradle.kts deleted file mode 100644 index 20eb7b4060..0000000000 --- a/samples/boot/kotlin-webflux/spring-security-samples-boot-kotlin-webflux.gradle.kts +++ /dev/null @@ -1,41 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - id("io.spring.convention.spring-sample-boot") - kotlin("jvm") - kotlin("plugin.spring") version "1.3.71" -} - -repositories { - mavenCentral() -} - -dependencies { - implementation(project(":spring-security-core")) - implementation(project(":spring-security-config")) - implementation(project(":spring-security-web")) - implementation("org.springframework.boot:spring-boot-starter-webflux") - implementation("org.springframework.boot:spring-boot-starter-thymeleaf") - implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity5") - implementation("io.projectreactor.kotlin:reactor-kotlin-extensions") - implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") - - testImplementation(project(":spring-security-test")) - testImplementation("org.springframework.boot:spring-boot-starter-test") { - exclude(group = "org.junit.vintage", module = "junit-vintage-engine") - } - testImplementation("io.projectreactor:reactor-test") -} - -tasks.withType { - useJUnitPlatform() -} - -tasks.withType { - kotlinOptions { - freeCompilerArgs = listOf("-Xjsr305=strict") - jvmTarget = "1.8" - } -} diff --git a/samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/KotlinWebfluxApplication.kt b/samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/KotlinWebfluxApplication.kt deleted file mode 100644 index 572be2a6e3..0000000000 --- a/samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/KotlinWebfluxApplication.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples - -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.runApplication - -@SpringBootApplication -class KotlinWebfluxApplication - -fun main(args: Array) { - runApplication(*args) -} diff --git a/samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/config/SecurityConfig.kt b/samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/config/SecurityConfig.kt deleted file mode 100644 index fcdb5fdcde..0000000000 --- a/samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/config/SecurityConfig.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config - -import org.springframework.context.annotation.Bean -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity -import org.springframework.security.config.web.server.ServerHttpSecurity -import org.springframework.security.config.web.server.invoke -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService -import org.springframework.security.core.userdetails.ReactiveUserDetailsService -import org.springframework.security.core.userdetails.User -import org.springframework.security.web.server.SecurityWebFilterChain - -@EnableWebFluxSecurity -class SecurityConfig { - - @Bean - fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - return http { - authorizeExchange { - authorize("/log-in", permitAll) - authorize("/", permitAll) - authorize("/css/**", permitAll) - authorize("/user/**", hasAuthority("ROLE_USER")) - } - formLogin { - loginPage = "/log-in" - } - } - } - - @Bean - fun userDetailsService(): ReactiveUserDetailsService { - val userDetails = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("USER") - .build() - return MapReactiveUserDetailsService(userDetails) - } -} diff --git a/samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/web/MainController.kt b/samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/web/MainController.kt deleted file mode 100644 index 991c0195c0..0000000000 --- a/samples/boot/kotlin-webflux/src/main/kotlin/org/springframework/security/samples/web/MainController.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.web - -import org.springframework.stereotype.Controller -import org.springframework.web.bind.annotation.GetMapping - -@Controller -class MainController { - - @GetMapping("/") - fun index(): String { - return "index" - } - - @GetMapping("/user/index") - fun userIndex(): String { - return "user/index" - } - - @GetMapping("/log-in") - fun login(): String { - return "login" - } -} diff --git a/samples/boot/kotlin-webflux/src/main/resources/application.yml b/samples/boot/kotlin-webflux/src/main/resources/application.yml deleted file mode 100644 index 8c01e005bc..0000000000 --- a/samples/boot/kotlin-webflux/src/main/resources/application.yml +++ /dev/null @@ -1,6 +0,0 @@ -server: - port: 8080 - -spring: - thymeleaf: - cache: false diff --git a/samples/boot/kotlin-webflux/src/main/resources/css/main.css b/samples/boot/kotlin-webflux/src/main/resources/css/main.css deleted file mode 100644 index de0941ecd5..0000000000 --- a/samples/boot/kotlin-webflux/src/main/resources/css/main.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - font-family: sans; - font-size: 1em; -} - -div.logout { - float: right; -} diff --git a/samples/boot/kotlin-webflux/src/main/resources/templates/index.html b/samples/boot/kotlin-webflux/src/main/resources/templates/index.html deleted file mode 100644 index f637854f04..0000000000 --- a/samples/boot/kotlin-webflux/src/main/resources/templates/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - Hello Spring Security - - - - -
- Logged in user: | - Roles: -
-
- -
-
-
-

Hello Spring Security

-

This is an unsecured page, but you can access the secured pages after authenticating.

- - - diff --git a/samples/boot/kotlin-webflux/src/main/resources/templates/login.html b/samples/boot/kotlin-webflux/src/main/resources/templates/login.html deleted file mode 100644 index 2ee9216937..0000000000 --- a/samples/boot/kotlin-webflux/src/main/resources/templates/login.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - Login page - - - - -

Login page

-

Example user: user / password

-
- : -
- : -
- -
-

Back to home page

- - diff --git a/samples/boot/kotlin-webflux/src/main/resources/templates/user/index.html b/samples/boot/kotlin-webflux/src/main/resources/templates/user/index.html deleted file mode 100644 index 393f6d3705..0000000000 --- a/samples/boot/kotlin-webflux/src/main/resources/templates/user/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - Hello Spring Security - - - - -
-

This is a secured page!

-

Back to home page

- - diff --git a/samples/boot/kotlin-webflux/src/test/kotlin/org/springframework/security/samples/KotlinWebfluxApplicationTests.kt b/samples/boot/kotlin-webflux/src/test/kotlin/org/springframework/security/samples/KotlinWebfluxApplicationTests.kt deleted file mode 100644 index fc126e58b7..0000000000 --- a/samples/boot/kotlin-webflux/src/test/kotlin/org/springframework/security/samples/KotlinWebfluxApplicationTests.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples - -import org.junit.jupiter.api.Test -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.context.ApplicationContext -import org.springframework.test.web.reactive.server.WebTestClient -import org.springframework.security.test.context.support.WithMockUser - -@SpringBootTest -class KotlinWebfluxApplicationTests { - - lateinit var rest: WebTestClient - - @Autowired - fun setup(context: ApplicationContext) { - rest = WebTestClient - .bindToApplicationContext(context) - .configureClient() - .build() - } - - @Test - fun `index page is not protected`() { - rest - .get() - .uri("/") - .exchange() - .expectStatus().isOk - } - - @Test - fun `protected page when unauthenticated then redirects to login `() { - rest - .get() - .uri("/user/index") - .exchange() - .expectStatus().is3xxRedirection - .expectHeader().valueEquals("Location", "/log-in") - } - - @Test - @WithMockUser - fun `protected page can be accessed when authenticated`() { - rest - .get() - .uri("/user/index") - .exchange() - .expectStatus().isOk - } -} diff --git a/samples/boot/kotlin/spring-security-samples-boot-kotlin.gradle.kts b/samples/boot/kotlin/spring-security-samples-boot-kotlin.gradle.kts deleted file mode 100644 index bd841b8b71..0000000000 --- a/samples/boot/kotlin/spring-security-samples-boot-kotlin.gradle.kts +++ /dev/null @@ -1,31 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - id("io.spring.convention.spring-sample-boot") - kotlin("jvm") - kotlin("plugin.spring") version "1.3.71" -} - -repositories { - mavenCentral() -} - -dependencies { - implementation(project(":spring-security-core")) - implementation(project(":spring-security-config")) - implementation(project(":spring-security-web")) - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-thymeleaf") - implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity5") - implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - testImplementation(project(":spring-security-test")) - testImplementation("org.springframework.boot:spring-boot-starter-test") -} - -tasks.withType { - kotlinOptions { - freeCompilerArgs = listOf("-Xjsr305=strict") - jvmTarget = "1.8" - } -} diff --git a/samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/KotlinApplication.kt b/samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/KotlinApplication.kt deleted file mode 100644 index 1d7c7b28f2..0000000000 --- a/samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/KotlinApplication.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.security.samples - -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.runApplication - -/** - * @author Eleftheria Stein - */ -@SpringBootApplication -class KotlinApplication - -fun main(args: Array) { - runApplication(*args) -} diff --git a/samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/config/SecurityConfig.kt b/samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/config/SecurityConfig.kt deleted file mode 100644 index 043f29ecae..0000000000 --- a/samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/config/SecurityConfig.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config - -import org.springframework.context.annotation.Bean -import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter -import org.springframework.security.config.web.servlet.invoke -import org.springframework.security.core.userdetails.User -import org.springframework.security.core.userdetails.UserDetailsService -import org.springframework.security.provisioning.InMemoryUserDetailsManager - -/** - * @author Eleftheria Stein - */ -@EnableWebSecurity -class SecurityConfig : WebSecurityConfigurerAdapter() { - - override fun configure(http: HttpSecurity) { - http { - authorizeRequests { - authorize("/css/**", permitAll) - authorize("/user/**", hasAuthority("ROLE_USER")) - } - formLogin { - loginPage = "/log-in" - } - } - } - - @Bean - public override fun userDetailsService(): UserDetailsService { - val userDetails = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("USER") - .build() - return InMemoryUserDetailsManager(userDetails) - } -} diff --git a/samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/web/MainController.kt b/samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/web/MainController.kt deleted file mode 100644 index e8c8128ad8..0000000000 --- a/samples/boot/kotlin/src/main/kotlin/org/springframework/security/samples/web/MainController.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.web - -import org.springframework.stereotype.Controller -import org.springframework.web.bind.annotation.GetMapping - -/** - * @author Eleftheria Stein - */ -@Controller -class MainController { - - @GetMapping("/") - fun index(): String { - return "index" - } - - @GetMapping("/user/index") - fun userIndex(): String { - return "user/index" - } - - @GetMapping("/log-in") - fun login(): String { - return "login" - } -} diff --git a/samples/boot/kotlin/src/main/resources/application.yml b/samples/boot/kotlin/src/main/resources/application.yml deleted file mode 100644 index 8c01e005bc..0000000000 --- a/samples/boot/kotlin/src/main/resources/application.yml +++ /dev/null @@ -1,6 +0,0 @@ -server: - port: 8080 - -spring: - thymeleaf: - cache: false diff --git a/samples/boot/kotlin/src/main/resources/static/css/main.css b/samples/boot/kotlin/src/main/resources/static/css/main.css deleted file mode 100644 index de0941ecd5..0000000000 --- a/samples/boot/kotlin/src/main/resources/static/css/main.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - font-family: sans; - font-size: 1em; -} - -div.logout { - float: right; -} diff --git a/samples/boot/kotlin/src/main/resources/templates/index.html b/samples/boot/kotlin/src/main/resources/templates/index.html deleted file mode 100644 index c30f4a8292..0000000000 --- a/samples/boot/kotlin/src/main/resources/templates/index.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - Hello Spring Security - - - - -
- Logged in user: | - Roles: -
-
- -
-
-
-

Hello Spring Security

-

This is an unsecured page, but you can access the secured pages after authenticating.

- - - diff --git a/samples/boot/kotlin/src/main/resources/templates/login.html b/samples/boot/kotlin/src/main/resources/templates/login.html deleted file mode 100644 index 2ee9216937..0000000000 --- a/samples/boot/kotlin/src/main/resources/templates/login.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - Login page - - - - -

Login page

-

Example user: user / password

-
- : -
- : -
- -
-

Back to home page

- - diff --git a/samples/boot/kotlin/src/main/resources/templates/user/index.html b/samples/boot/kotlin/src/main/resources/templates/user/index.html deleted file mode 100644 index b36caed027..0000000000 --- a/samples/boot/kotlin/src/main/resources/templates/user/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - Hello Spring Security - - - - -
-

This is a secured page!

-

Back to home page

- - diff --git a/samples/boot/kotlin/src/test/kotlin/org/springframework/security/samples/KotlinApplicationTests.kt b/samples/boot/kotlin/src/test/kotlin/org/springframework/security/samples/KotlinApplicationTests.kt deleted file mode 100644 index 393bb0f2e2..0000000000 --- a/samples/boot/kotlin/src/test/kotlin/org/springframework/security/samples/KotlinApplicationTests.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples - -import org.assertj.core.api.Assertions.assertThat -import org.junit.Test -import org.junit.runner.RunWith -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.mock.web.MockHttpSession -import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin -import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated -import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated -import org.springframework.test.context.junit4.SpringRunner -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.get -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status - -@RunWith(SpringRunner::class) -@SpringBootTest -@AutoConfigureMockMvc -class KotlinApplicationTests { - - @Autowired - private lateinit var mockMvc: MockMvc - - @Test - fun `index page is not protected`() { - this.mockMvc.get("/") - .andExpect { - status { isOk() } - } - } - - @Test - fun `protected page redirects to login`() { - val mvcResult = this.mockMvc.get("/user/index") - .andExpect { status { is3xxRedirection() } } - .andReturn() - - assertThat(mvcResult.response.redirectedUrl).endsWith("/log-in") - } - - @Test - fun `valid user permitted to log in`() { - this.mockMvc.perform(formLogin("/log-in").user("user").password("password")) - .andExpect(authenticated()) - } - - @Test - fun `invalid user not permitted to log in`() { - this.mockMvc.perform(formLogin("/log-in").user("invalid").password("invalid")) - .andExpect(unauthenticated()) - .andExpect(status().is3xxRedirection) - } - - @Test - fun `logged in user can access protected page`() { - val mvcResult = this.mockMvc.perform(formLogin("/log-in").user("user").password("password")) - .andExpect(authenticated()).andReturn() - - val httpSession = mvcResult.request.getSession(false) as MockHttpSession - - this.mockMvc.get("/user/index") { - session = httpSession - }.andExpect { - status { isOk() } - } - } -} diff --git a/samples/boot/oauth2authorizationserver/README.adoc b/samples/boot/oauth2authorizationserver/README.adoc deleted file mode 100644 index e056a21b17..0000000000 --- a/samples/boot/oauth2authorizationserver/README.adoc +++ /dev/null @@ -1,39 +0,0 @@ -= OAuth 2.0 Authorization Server Sample - -This sample demonstrates an Authorization Server that supports a simple, static JWK Set. - -It's useful for working with the other samples in the library that want to point to an Authorization Server. - -== 1. Running the server - -To run the server, do: - -```bash -./gradlew bootRun -``` - -Or import the project into your IDE and run `OAuth2AuthorizationServerApplication` from there. - -Once it is up, this request asks for a token with the "message:read" scope: - -```bash -curl reader:secret@localhost:8081/oauth/token -d grant_type=password -d username=subject -d password=password -``` - -Which will respond with something like: - -```json -{ - "access_token":"eyJhbGciOiJSUzI1NiIsI...Fhq4RIVyA4ZAkC7T1aZbKAQ", - "token_type":"bearer", - "expires_in":599999999, - "scope":"message:read", - "jti":"8a425df7-f4c9-4ca4-be12-0136c3015da0" -} -``` - -You can also do the same with the `writer` client: - -```bash -curl writer:secret@localhost:8081/oauth/token -d grant_type=password -d username=subject -d password=password -``` diff --git a/samples/boot/oauth2authorizationserver/spring-security-samples-boot-oauth2authorizationserver.gradle b/samples/boot/oauth2authorizationserver/spring-security-samples-boot-oauth2authorizationserver.gradle deleted file mode 100644 index 3b2df4e605..0000000000 --- a/samples/boot/oauth2authorizationserver/spring-security-samples-boot-oauth2authorizationserver.gradle +++ /dev/null @@ -1,14 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'org.springframework.boot:spring-boot-starter-security' - compile "org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:${springBootVersion}" - - compile 'javax.xml.bind:jaxb-api' - compile 'com.sun.xml.bind:jaxb-core' - compile 'com.sun.xml.bind:jaxb-impl' - compile 'com.nimbusds:nimbus-jose-jwt' - - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/oauth2authorizationserver/src/main/java/sample/AuthorizationServerConfiguration.java b/samples/boot/oauth2authorizationserver/src/main/java/sample/AuthorizationServerConfiguration.java deleted file mode 100644 index 4b20b0c88c..0000000000 --- a/samples/boot/oauth2authorizationserver/src/main/java/sample/AuthorizationServerConfiguration.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.RSAPrivateKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.stream.Collectors; - -import com.nimbusds.jose.jwk.JWKSet; -import com.nimbusds.jose.jwk.RSAKey; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpoint; -import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; -import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter; -import org.springframework.security.oauth2.provider.token.TokenStore; -import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore; -import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; -import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -/** - * An instance of Legacy Authorization Server (spring-security-oauth2) that uses a single, - * not-rotating key and exposes a JWK endpoint. - * - * See - * - * Spring Security OAuth Autoconfig's documentation for additional detail - * - * @author Josh Cummings - * @since 5.1 - */ -@EnableAuthorizationServer -@Configuration -public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { - - AuthenticationManager authenticationManager; - KeyPair keyPair; - boolean jwtEnabled; - - public AuthorizationServerConfiguration( - AuthenticationConfiguration authenticationConfiguration, - KeyPair keyPair, - @Value("${security.oauth2.authorizationserver.jwt.enabled:true}") boolean jwtEnabled) throws Exception { - - this.authenticationManager = authenticationConfiguration.getAuthenticationManager(); - this.keyPair = keyPair; - this.jwtEnabled = jwtEnabled; - } - - @Override - public void configure(ClientDetailsServiceConfigurer clients) - throws Exception { - // @formatter:off - clients.inMemory() - .withClient("reader") - .authorizedGrantTypes("password") - .secret("{noop}secret") - .scopes("message:read") - .accessTokenValiditySeconds(600_000_000) - .and() - .withClient("writer") - .authorizedGrantTypes("password") - .secret("{noop}secret") - .scopes("message:write") - .accessTokenValiditySeconds(600_000_000) - .and() - .withClient("noscopes") - .authorizedGrantTypes("password") - .secret("{noop}secret") - .scopes("none") - .accessTokenValiditySeconds(600_000_000); - // @formatter:on - } - - @Override - public void configure(AuthorizationServerEndpointsConfigurer endpoints) { - // @formatter:off - endpoints - .authenticationManager(this.authenticationManager) - .tokenStore(tokenStore()); - - if (this.jwtEnabled) { - endpoints - .accessTokenConverter(accessTokenConverter()); - } - // @formatter:on - } - - @Bean - public TokenStore tokenStore() { - if (this.jwtEnabled) { - return new JwtTokenStore(accessTokenConverter()); - } else { - return new InMemoryTokenStore(); - } - } - - @Bean - public JwtAccessTokenConverter accessTokenConverter() { - JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); - converter.setKeyPair(this.keyPair); - - DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); - accessTokenConverter.setUserTokenConverter(new SubjectAttributeUserTokenConverter()); - converter.setAccessTokenConverter(accessTokenConverter); - - return converter; - } -} - -/** - * For configuring the end users recognized by this Authorization Server - */ -@Configuration -class UserConfig extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .mvcMatchers("/.well-known/jwks.json").permitAll() - .anyRequest().authenticated() - .and() - .httpBasic() - .and() - .csrf().ignoringRequestMatchers((request) -> "/introspect".equals(request.getRequestURI())); - } - - @Bean - @Override - public UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager( - User.withDefaultPasswordEncoder() - .username("subject") - .password("password") - .roles("USER") - .build()); - } -} - -/** - * Legacy Authorization Server (spring-security-oauth2) does not support any - * Token Introspection endpoint. - * - * This class adds ad-hoc support in order to better support the other samples in the repo. - */ -@FrameworkEndpoint -class IntrospectEndpoint { - TokenStore tokenStore; - - IntrospectEndpoint(TokenStore tokenStore) { - this.tokenStore = tokenStore; - } - - @PostMapping("/introspect") - @ResponseBody - public Map introspect(@RequestParam("token") String token) { - OAuth2AccessToken accessToken = this.tokenStore.readAccessToken(token); - Map attributes = new HashMap<>(); - if (accessToken == null || accessToken.isExpired()) { - attributes.put("active", false); - return attributes; - } - - OAuth2Authentication authentication = this.tokenStore.readAuthentication(token); - - attributes.put("active", true); - attributes.put("exp", accessToken.getExpiration().getTime()); - attributes.put("scope", accessToken.getScope().stream().collect(Collectors.joining(" "))); - attributes.put("sub", authentication.getName()); - - return attributes; - } -} - -/** - * Legacy Authorization Server (spring-security-oauth2) does not support any - * JWK Set endpoint. - * - * This class adds ad-hoc support in order to better support the other samples in the repo. - */ -@FrameworkEndpoint -class JwkSetEndpoint { - KeyPair keyPair; - - JwkSetEndpoint(KeyPair keyPair) { - this.keyPair = keyPair; - } - - @GetMapping("/.well-known/jwks.json") - @ResponseBody - public Map getKey() { - RSAPublicKey publicKey = (RSAPublicKey) this.keyPair.getPublic(); - RSAKey key = new RSAKey.Builder(publicKey).build(); - return new JWKSet(key).toJSONObject(); - } -} - -/** - * An Authorization Server will more typically have a key rotation strategy, and the keys will not - * be hard-coded into the application code. - * - * For simplicity, though, this sample doesn't demonstrate key rotation. - */ -@Configuration -class KeyConfig { - @Bean - KeyPair keyPair() { - try { - String privateExponent = "3851612021791312596791631935569878540203393691253311342052463788814433805390794604753109719790052408607029530149004451377846406736413270923596916756321977922303381344613407820854322190592787335193581632323728135479679928871596911841005827348430783250026013354350760878678723915119966019947072651782000702927096735228356171563532131162414366310012554312756036441054404004920678199077822575051043273088621405687950081861819700809912238863867947415641838115425624808671834312114785499017269379478439158796130804789241476050832773822038351367878951389438751088021113551495469440016698505614123035099067172660197922333993"; - String modulus = "18044398961479537755088511127417480155072543594514852056908450877656126120801808993616738273349107491806340290040410660515399239279742407357192875363433659810851147557504389760192273458065587503508596714389889971758652047927503525007076910925306186421971180013159326306810174367375596043267660331677530921991343349336096643043840224352451615452251387611820750171352353189973315443889352557807329336576421211370350554195530374360110583327093711721857129170040527236951522127488980970085401773781530555922385755722534685479501240842392531455355164896023070459024737908929308707435474197069199421373363801477026083786683"; - String exponent = "65537"; - - RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(exponent)); - RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(new BigInteger(modulus), new BigInteger(privateExponent)); - KeyFactory factory = KeyFactory.getInstance("RSA"); - return new KeyPair(factory.generatePublic(publicSpec), factory.generatePrivate(privateSpec)); - } catch ( Exception e ) { - throw new IllegalArgumentException(e); - } - } -} - -/** - * Legacy Authorization Server does not support a custom name for the user parameter, so we'll need - * to extend the default. By default, it uses the attribute {@code user_name}, though it would be - * better to adhere to the {@code sub} property defined in the - * JWT Specification. - */ -class SubjectAttributeUserTokenConverter extends DefaultUserAuthenticationConverter { - @Override - public Map convertUserAuthentication(Authentication authentication) { - Map response = new LinkedHashMap<>(); - response.put("sub", authentication.getName()); - if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) { - response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities())); - } - return response; - } -} diff --git a/samples/boot/oauth2authorizationserver/src/main/java/sample/OAuth2AuthorizationServerApplication.java b/samples/boot/oauth2authorizationserver/src/main/java/sample/OAuth2AuthorizationServerApplication.java deleted file mode 100644 index 13602ec74e..0000000000 --- a/samples/boot/oauth2authorizationserver/src/main/java/sample/OAuth2AuthorizationServerApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Josh Cummings - */ -@SpringBootApplication -public class OAuth2AuthorizationServerApplication { - - public static void main(String[] args) { - SpringApplication.run(OAuth2AuthorizationServerApplication.class, args); - } -} diff --git a/samples/boot/oauth2authorizationserver/src/main/resources/application.yml b/samples/boot/oauth2authorizationserver/src/main/resources/application.yml deleted file mode 100644 index b0b10a294f..0000000000 --- a/samples/boot/oauth2authorizationserver/src/main/resources/application.yml +++ /dev/null @@ -1,3 +0,0 @@ -server.port: 8081 - -# security.oauth2.authorizationserver.jwt.enabled: false diff --git a/samples/boot/oauth2authorizationserver/src/test/java/sample/OAuth2AuthorizationServerApplicationTests.java b/samples/boot/oauth2authorizationserver/src/test/java/sample/OAuth2AuthorizationServerApplicationTests.java deleted file mode 100644 index 05377bf3f8..0000000000 --- a/samples/boot/oauth2authorizationserver/src/test/java/sample/OAuth2AuthorizationServerApplicationTests.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * Tests for {@link OAuth2AuthorizationServerApplication} - * - * @author Josh Cummings - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -public class OAuth2AuthorizationServerApplicationTests { - - @Autowired - MockMvc mvc; - - @Test - public void requestTokenWhenUsingPasswordGrantTypeThenOk() - throws Exception { - - this.mvc.perform(post("/oauth/token") - .param("grant_type", "password") - .param("username", "subject") - .param("password", "password") - .header("Authorization", "Basic cmVhZGVyOnNlY3JldA==")) - .andExpect(status().isOk()); - } - - @Test - public void requestJwkSetWhenUsingDefaultsThenOk() - throws Exception { - - this.mvc.perform(get("/.well-known/jwks.json")) - .andExpect(status().isOk()); - } - -} diff --git a/samples/boot/oauth2login-webflux/README.adoc b/samples/boot/oauth2login-webflux/README.adoc deleted file mode 100644 index a96fec395b..0000000000 --- a/samples/boot/oauth2login-webflux/README.adoc +++ /dev/null @@ -1,324 +0,0 @@ -NOTE: Spring Security Reactive OAuth only supports authentication using a user info endpoint. -Support for JWT validation will be added in https://github.com/spring-projects/spring-security/issues/5330[gh-5330]. - -= OAuth 2.0 Login Sample - -This guide provides instructions on setting up the sample application with OAuth 2.0 Login using an OAuth 2.0 Provider or OpenID Connect 1.0 Provider. -The sample application uses Spring Boot 2.0.0.M6 and the `spring-security-oauth2-client` module which is new in Spring Security 5.0. - -The following sections provide detailed steps for setting up OAuth 2.0 Login for these Providers: - -* <> -* <> -* <> -* <> - -[[google-login]] -== Login with Google - -This section shows how to configure the sample application using Google as the Authentication Provider and covers the following topics: - -* <> -* <> -* <> -* <> - -[[google-initial-setup]] -=== Initial setup - -To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. - -NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the - https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. - -Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0". - -After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret. - -[[google-redirect-uri]] -=== Setting the redirect URI - -The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google -and have granted access to the OAuth Client _(created in the previous step)_ on the Consent page. - -In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. - -TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`. - The *_registrationId_* is a unique identifier for the `ClientRegistration`. - -IMPORTANT: If the application is running behind a proxy server, it is recommended to check https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#appendix-proxy-server[Proxy Server Configuration] to ensure the application is correctly configured. -Also, see the supported https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2Client-auth-code-redirect-uri[`URI` template variables] for `redirect-uri`. - -[[google-application-config]] -=== Configure application.yml - -Now that you have a new OAuth Client with Google, you need to configure the application to use the OAuth Client for the _authentication flow_. To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - google: <2> - client-id: google-client-id - client-secret: google-client-secret ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, such as google. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. - -[[google-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ login page, which displays a link for Google. - -Click on the Google link, and you are then redirected to Google for authentication. - -After authenticating with your Google account credentials, the next page presented to you is the Consent screen. -The Consent screen asks you to either allow or deny access to the OAuth Client you created earlier. -Click *Allow* to authorize the OAuth Client to access your email address and basic profile information. - -At this point, the OAuth Client retrieves your email address and basic profile information -from the https://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] and establishes an authenticated session. - -[[github-login]] -== Login with GitHub - -This section shows how to configure the sample application using GitHub as the Authentication Provider and covers the following topics: - -* <> -* <> -* <> - -[[github-register-application]] -=== Register OAuth application - -To use GitHub's OAuth 2.0 authentication system for login, you must https://github.com/settings/applications/new[Register a new OAuth application]. - -When registering the OAuth application, ensure the *Authorization callback URL* is set to `http://localhost:8080/login/oauth2/code/github`. - -The Authorization callback URL (redirect URI) is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with GitHub -and have granted access to the OAuth application on the _Authorize application_ page. - -TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`. - The *_registrationId_* is a unique identifier for the `ClientRegistration`. - -IMPORTANT: If the application is running behind a proxy server, it is recommended to check https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#appendix-proxy-server[Proxy Server Configuration] to ensure the application is correctly configured. -Also, see the supported https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2Client-auth-code-redirect-uri[`URI` template variables] for `redirect-uri`. - -[[github-application-config]] -=== Configure application.yml - -Now that you have a new OAuth application with GitHub, you need to configure the application to use the OAuth application for the _authentication flow_. To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - github: <2> - client-id: github-client-id - client-secret: github-client-secret ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, such as github. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. - -[[github-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ login page, which displays a link for GitHub. - -Click on the GitHub link, and you are then redirected to GitHub for authentication. - -After authenticating with your GitHub credentials, the next page presented to you is "Authorize application". -This page will ask you to *Authorize* the application you created in the previous step. -Click _Authorize application_ to allow the OAuth application to access your personal user data information. - -At this point, the OAuth Client retrieves your personal user information -from the UserInfo Endpoint and establishes an authenticated session. - -[TIP] -For detailed information returned from the UserInfo Endpoint, see the API documentation -for https://developer.github.com/v3/users/#get-the-authenticated-user["Get the authenticated user"]. - -[[facebook-login]] -== Login with Facebook - -This section shows how to configure the sample application using Facebook as the Authentication Provider and covers the following topics: - -* <> -* <> -* <> - -[[facebook-register-application]] -=== Add a New App - -To use Facebook's OAuth 2.0 authentication system for login, you must first https://developers.facebook.com/apps[Add a New App]. - -Select "Create a New App" and then the "Create a New App ID" page is presented. Enter the Display Name, Contact Email, Category and then click "Create App ID". - -NOTE: The selection for the _Category_ field is not relevant but it's a required field - select "Local". - -The next page presented is "Product Setup". Click the "Get Started" button for the *Facebook Login* product. -In the left sidebar, under _Products -> Facebook Login_, select _Settings_. - -For the field *Valid OAuth redirect URIs*, enter `http://localhost:8080/login/oauth2/code/facebook` then click _Save Changes_. - -The OAuth redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Facebook -and have granted access to the application on the _Authorize application_ page. - -TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`. - The *_registrationId_* is a unique identifier for the `ClientRegistration`. - -IMPORTANT: If the application is running behind a proxy server, it is recommended to check https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#appendix-proxy-server[Proxy Server Configuration] to ensure the application is correctly configured. -Also, see the supported https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2Client-auth-code-redirect-uri[`URI` template variables] for `redirect-uri`. - -[[facebook-application-config]] -=== Configure application.yml - -Now that you have created a new application with Facebook, you need to configure the sample application to use the application for the _authentication flow_. To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - facebook: <2> - client-id: facebook-client-id - client-secret: facebook-client-secret ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, such as facebook. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. - -[[facebook-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ login page, which displays a link for Facebook. - -Click on the Facebook link, and you are then redirected to Facebook for authentication. - -After authenticating with your Facebook credentials, the next page presented to you is "Authorize application". -This page will ask you to *Authorize* the application you created in the previous step. -Click _Authorize application_ to allow the OAuth application to access your _public profile_ and _email address_ information. - -At this point, the OAuth Client retrieves your personal user information -from the UserInfo Endpoint and establishes an authenticated session. - -[[okta-login]] -== Login with Okta - -This section shows how to configure the sample application using Okta as the Authentication Provider and covers the following topics: - -* <> -* <> -* <> -* <> - -[[okta-register-application]] -=== Add Application - -To use Okta's OAuth 2.0 authentication system for login, you must first https://www.okta.com/developer/signup[create a developer account]. - -Sign in to your account sub-domain and navigate to _Applications -> Applications_ and then select the "Add Application" button. -From the "Add Application" page, select the "Create New App" button and enter the following: - -* *Platform:* Web -* *Sign on method:* OpenID Connect - -Select the _Create_ button. -On the "General Settings" page, enter the Application Name (for example, "Spring Security Okta Login") and then select the _Next_ button. -On the "Configure OpenID Connect" page, enter `http://localhost:8080/login/oauth2/code/okta` for the field *Redirect URIs* and then select _Finish_. - -The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Okta -and have granted access to the application on the _Authorize application_ page. - -TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`. - The *_registrationId_* is a unique identifier for the `ClientRegistration`. - -IMPORTANT: If the application is running behind a proxy server, it is recommended to check https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#appendix-proxy-server[Proxy Server Configuration] to ensure the application is correctly configured. -Also, see the supported https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2Client-auth-code-redirect-uri[`URI` template variables] for `redirect-uri`. - -[[okta-assign-application-people]] -=== Assign Application to People - -From the "General" tab of the application, select the "Assignments" tab and then select the _Assign_ button. -Select _Assign to People_ and assign your account to the application. Then select the _Save and Go Back_ button. - -[[okta-application-config]] -=== Configure application.yml - -Now that you have created a new application with Okta, you need to configure the sample application to use the application for the _authentication flow_. To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - okta: <2> - client-id: okta-client-id - client-secret: okta-client-secret - provider: <3> - okta: - authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize - token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token - user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo - user-name-attribute: sub - jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, such as okta. -<3> `spring.security.oauth2.client.provider` is the base property prefix for OAuth Provider properties. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. -As well, replace `https://your-subdomain.oktapreview.com` in `authorization-uri`, `token-uri`, `user-info-uri` and `jwk-set-uri` with the sub-domain assigned to your account during the registration process. - -[[okta-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ login page, which displays a link for Okta. - -Click on the Okta link, and you are then redirected to Okta for authentication. - -After authenticating with your Okta account credentials, the OAuth Client retrieves your email address and basic profile information -from the https://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] and establishes an authenticated session. diff --git a/samples/boot/oauth2login-webflux/spring-security-samples-boot-oauth2login-webflux.gradle b/samples/boot/oauth2login-webflux/spring-security-samples-boot-oauth2login-webflux.gradle deleted file mode 100644 index 49099dbd7a..0000000000 --- a/samples/boot/oauth2login-webflux/spring-security-samples-boot-oauth2login-webflux.gradle +++ /dev/null @@ -1,14 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-client') - compile project(':spring-security-oauth2-jose') - compile 'org.springframework.boot:spring-boot-starter-thymeleaf' - compile 'org.springframework.boot:spring-boot-starter-webflux' - compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' - - testCompile project(':spring-security-test') - testCompile 'net.sourceforge.htmlunit:htmlunit' - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/oauth2login-webflux/src/integration-test/java/sample/OAuth2LoginApplicationTests.java b/samples/boot/oauth2login-webflux/src/integration-test/java/sample/OAuth2LoginApplicationTests.java deleted file mode 100644 index c3e2b63af6..0000000000 --- a/samples/boot/oauth2login-webflux/src/integration-test/java/sample/OAuth2LoginApplicationTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -import static org.hamcrest.core.StringContains.containsString; -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Login; - -/** - * Tests for {@link ReactiveOAuth2LoginApplication} - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureWebTestClient -public class OAuth2LoginApplicationTests { - - @Autowired - WebTestClient test; - - @Autowired - ReactiveClientRegistrationRepository clientRegistrationRepository; - - @Test - public void requestWhenMockOidcLoginThenIndex() { - this.clientRegistrationRepository.findByRegistrationId("github") - .map((clientRegistration) -> - this.test.mutateWith(mockOAuth2Login().clientRegistration(clientRegistration)) - .get().uri("/") - .exchange() - .expectBody(String.class).value(containsString("GitHub")) - ).block(); - } -} diff --git a/samples/boot/oauth2login-webflux/src/main/java/sample/ReactiveOAuth2LoginApplication.java b/samples/boot/oauth2login-webflux/src/main/java/sample/ReactiveOAuth2LoginApplication.java deleted file mode 100644 index f6fd94e849..0000000000 --- a/samples/boot/oauth2login-webflux/src/main/java/sample/ReactiveOAuth2LoginApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Rob Winch - */ -@SpringBootApplication -public class ReactiveOAuth2LoginApplication { - - public static void main(String[] args) { - SpringApplication.run(ReactiveOAuth2LoginApplication.class, args); - } - -} diff --git a/samples/boot/oauth2login-webflux/src/main/java/sample/web/OAuth2LoginController.java b/samples/boot/oauth2login-webflux/src/main/java/sample/web/OAuth2LoginController.java deleted file mode 100644 index 2e03a6adcd..0000000000 --- a/samples/boot/oauth2login-webflux/src/main/java/sample/web/OAuth2LoginController.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.web; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; -import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; - -/** - * @author Rob Winch - */ -@Controller -public class OAuth2LoginController { - - @GetMapping("/") - public String index(Model model, - @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient, - @AuthenticationPrincipal OAuth2User oauth2User) { - model.addAttribute("userName", oauth2User.getName()); - model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName()); - model.addAttribute("userAttributes", oauth2User.getAttributes()); - return "index"; - } -} diff --git a/samples/boot/oauth2login-webflux/src/main/resources/application.yml b/samples/boot/oauth2login-webflux/src/main/resources/application.yml deleted file mode 100644 index 73b08fbd83..0000000000 --- a/samples/boot/oauth2login-webflux/src/main/resources/application.yml +++ /dev/null @@ -1,35 +0,0 @@ -server: - port: 8080 - -logging: - level: - root: INFO - org.springframework.web: INFO - org.springframework.security: INFO -# org.springframework.boot.autoconfigure: DEBUG - -spring: - thymeleaf: - cache: false - security: - oauth2: - client: - registration: - google: - client-id: your-app-client-id - client-secret: your-app-client-secret - github: - client-id: your-app-client-id - client-secret: your-app-client-secret - facebook: - client-id: your-app-client-id - client-secret: your-app-client-secret - okta: - client-id: your-app-client-id - client-secret: your-app-client-secret - provider: - okta: - authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize - token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token - user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo - jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys diff --git a/samples/boot/oauth2login-webflux/src/main/resources/templates/index.html b/samples/boot/oauth2login-webflux/src/main/resources/templates/index.html deleted file mode 100644 index ce8cdcde23..0000000000 --- a/samples/boot/oauth2login-webflux/src/main/resources/templates/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - Spring Security - OAuth 2.0 Login - - - -
-
- User: -
-
 
-
- Log Out -
-
-

OAuth 2.0 Login with Spring Security

-
- You are successfully logged in - via the OAuth 2.0 Client -
-
 
-
- User Attributes: -
    -
  • - : -
  • -
-
- - diff --git a/samples/boot/oauth2login-webflux/src/test/java/sample/OAuth2LoginControllerTests.java b/samples/boot/oauth2login-webflux/src/test/java/sample/OAuth2LoginControllerTests.java deleted file mode 100644 index 11ae5f8ba6..0000000000 --- a/samples/boot/oauth2login-webflux/src/test/java/sample/OAuth2LoginControllerTests.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import sample.web.OAuth2LoginController; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.core.ReactiveAdapterRegistry; -import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; -import org.springframework.security.oauth2.client.web.reactive.result.method.annotation.OAuth2AuthorizedClientArgumentResolver; -import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; -import org.springframework.security.web.reactive.result.method.annotation.AuthenticationPrincipalArgumentResolver; -import org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.web.reactive.result.view.ViewResolver; - -import static org.hamcrest.Matchers.containsString; -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Login; -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity; - -/** - * @author Josh Cummings - */ -@RunWith(SpringRunner.class) -@WebFluxTest(OAuth2LoginController.class) -public class OAuth2LoginControllerTests { - - @Autowired - OAuth2LoginController controller; - - @Autowired - ViewResolver viewResolver; - - @Mock - ReactiveClientRegistrationRepository clientRegistrationRepository; - - @Mock - ServerOAuth2AuthorizedClientRepository authorizedClientRepository; - - WebTestClient rest; - - @Before - public void setup() { - this.rest = WebTestClient - .bindToController(this.controller) - .apply(springSecurity()) - .webFilter(new SecurityContextServerWebExchangeWebFilter()) - .argumentResolvers((c) -> { - c.addCustomResolver(new AuthenticationPrincipalArgumentResolver(new ReactiveAdapterRegistry())); - c.addCustomResolver(new OAuth2AuthorizedClientArgumentResolver - (this.clientRegistrationRepository, this.authorizedClientRepository)); - }) - .viewResolvers((c) -> c.viewResolver(this.viewResolver)) - .build(); - } - - @Test - public void indexGreetsAuthenticatedUser() { - this.rest.mutateWith(mockOAuth2Login()) - .get().uri("/").exchange() - .expectBody(String.class).value(containsString("user")); - } -} diff --git a/samples/boot/oauth2login/README.adoc b/samples/boot/oauth2login/README.adoc deleted file mode 100644 index e949a7f84e..0000000000 --- a/samples/boot/oauth2login/README.adoc +++ /dev/null @@ -1,321 +0,0 @@ -= OAuth 2.0 Login Sample - -This guide provides instructions on setting up the sample application with OAuth 2.0 Login using an OAuth 2.0 Provider or OpenID Connect 1.0 Provider. -The sample application uses Spring Boot 2.0.0.M6 and the `spring-security-oauth2-client` module which is new in Spring Security 5.0. - -The following sections provide detailed steps for setting up OAuth 2.0 Login for these Providers: - -* <> -* <> -* <> -* <> - -[[google-login]] -== Login with Google - -This section shows how to configure the sample application using Google as the Authentication Provider and covers the following topics: - -* <> -* <> -* <> -* <> - -[[google-initial-setup]] -=== Initial setup - -To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. - -NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the - https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. - -Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0". - -After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret. - -[[google-redirect-uri]] -=== Setting the redirect URI - -The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google -and have granted access to the OAuth Client _(created in the previous step)_ on the Consent page. - -In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. - -TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`. - The *_registrationId_* is a unique identifier for the `ClientRegistration`. - -IMPORTANT: If the application is running behind a proxy server, it is recommended to check https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#appendix-proxy-server[Proxy Server Configuration] to ensure the application is correctly configured. -Also, see the supported https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2Client-auth-code-redirect-uri[`URI` template variables] for `redirect-uri`. - -[[google-application-config]] -=== Configure application.yml - -Now that you have a new OAuth Client with Google, you need to configure the application to use the OAuth Client for the _authentication flow_. To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - google: <2> - client-id: google-client-id - client-secret: google-client-secret ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, such as google. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. - -[[google-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ login page, which displays a link for Google. - -Click on the Google link, and you are then redirected to Google for authentication. - -After authenticating with your Google account credentials, the next page presented to you is the Consent screen. -The Consent screen asks you to either allow or deny access to the OAuth Client you created earlier. -Click *Allow* to authorize the OAuth Client to access your email address and basic profile information. - -At this point, the OAuth Client retrieves your email address and basic profile information -from the https://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] and establishes an authenticated session. - -[[github-login]] -== Login with GitHub - -This section shows how to configure the sample application using GitHub as the Authentication Provider and covers the following topics: - -* <> -* <> -* <> - -[[github-register-application]] -=== Register OAuth application - -To use GitHub's OAuth 2.0 authentication system for login, you must https://github.com/settings/applications/new[Register a new OAuth application]. - -When registering the OAuth application, ensure the *Authorization callback URL* is set to `http://localhost:8080/login/oauth2/code/github`. - -The Authorization callback URL (redirect URI) is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with GitHub -and have granted access to the OAuth application on the _Authorize application_ page. - -TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`. - The *_registrationId_* is a unique identifier for the `ClientRegistration`. - -IMPORTANT: If the application is running behind a proxy server, it is recommended to check https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#appendix-proxy-server[Proxy Server Configuration] to ensure the application is correctly configured. -Also, see the supported https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2Client-auth-code-redirect-uri[`URI` template variables] for `redirect-uri`. - -[[github-application-config]] -=== Configure application.yml - -Now that you have a new OAuth application with GitHub, you need to configure the application to use the OAuth application for the _authentication flow_. To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - github: <2> - client-id: github-client-id - client-secret: github-client-secret ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, such as github. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. - -[[github-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ login page, which displays a link for GitHub. - -Click on the GitHub link, and you are then redirected to GitHub for authentication. - -After authenticating with your GitHub credentials, the next page presented to you is "Authorize application". -This page will ask you to *Authorize* the application you created in the previous step. -Click _Authorize application_ to allow the OAuth application to access your personal user data information. - -At this point, the OAuth Client retrieves your personal user information -from the UserInfo Endpoint and establishes an authenticated session. - -[TIP] -For detailed information returned from the UserInfo Endpoint, see the API documentation -for https://developer.github.com/v3/users/#get-the-authenticated-user["Get the authenticated user"]. - -[[facebook-login]] -== Login with Facebook - -This section shows how to configure the sample application using Facebook as the Authentication Provider and covers the following topics: - -* <> -* <> -* <> - -[[facebook-register-application]] -=== Add a New App - -To use Facebook's OAuth 2.0 authentication system for login, you must first https://developers.facebook.com/apps[Add a New App]. - -Select "Create a New App" and then the "Create a New App ID" page is presented. Enter the Display Name, Contact Email, Category and then click "Create App ID". - -NOTE: The selection for the _Category_ field is not relevant but it's a required field - select "Local". - -The next page presented is "Product Setup". Click the "Get Started" button for the *Facebook Login* product. -In the left sidebar, under _Products -> Facebook Login_, select _Settings_. - -For the field *Valid OAuth redirect URIs*, enter `http://localhost:8080/login/oauth2/code/facebook` then click _Save Changes_. - -The OAuth redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Facebook -and have granted access to the application on the _Authorize application_ page. - -TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`. - The *_registrationId_* is a unique identifier for the `ClientRegistration`. - -IMPORTANT: If the application is running behind a proxy server, it is recommended to check https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#appendix-proxy-server[Proxy Server Configuration] to ensure the application is correctly configured. -Also, see the supported https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2Client-auth-code-redirect-uri[`URI` template variables] for `redirect-uri`. - -[[facebook-application-config]] -=== Configure application.yml - -Now that you have created a new application with Facebook, you need to configure the sample application to use the application for the _authentication flow_. To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - facebook: <2> - client-id: facebook-client-id - client-secret: facebook-client-secret ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, such as facebook. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. - -[[facebook-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ login page, which displays a link for Facebook. - -Click on the Facebook link, and you are then redirected to Facebook for authentication. - -After authenticating with your Facebook credentials, the next page presented to you is "Authorize application". -This page will ask you to *Authorize* the application you created in the previous step. -Click _Authorize application_ to allow the OAuth application to access your _public profile_ and _email address_ information. - -At this point, the OAuth Client retrieves your personal user information -from the UserInfo Endpoint and establishes an authenticated session. - -[[okta-login]] -== Login with Okta - -This section shows how to configure the sample application using Okta as the Authentication Provider and covers the following topics: - -* <> -* <> -* <> -* <> - -[[okta-register-application]] -=== Add Application - -To use Okta's OAuth 2.0 authentication system for login, you must first https://www.okta.com/developer/signup[create a developer account]. - -Sign in to your account sub-domain and navigate to _Applications -> Applications_ and then select the "Add Application" button. -From the "Add Application" page, select the "Create New App" button and enter the following: - -* *Platform:* Web -* *Sign on method:* OpenID Connect - -Select the _Create_ button. -On the "General Settings" page, enter the Application Name (for example, "Spring Security Okta Login") and then select the _Next_ button. -On the "Configure OpenID Connect" page, enter `http://localhost:8080/login/oauth2/code/okta` for the field *Redirect URIs* and then select _Finish_. - -The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Okta -and have granted access to the application on the _Authorize application_ page. - -TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`. - The *_registrationId_* is a unique identifier for the `ClientRegistration`. - -IMPORTANT: If the application is running behind a proxy server, it is recommended to check https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#appendix-proxy-server[Proxy Server Configuration] to ensure the application is correctly configured. -Also, see the supported https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2Client-auth-code-redirect-uri[`URI` template variables] for `redirect-uri`. - -[[okta-assign-application-people]] -=== Assign Application to People - -From the "General" tab of the application, select the "Assignments" tab and then select the _Assign_ button. -Select _Assign to People_ and assign your account to the application. Then select the _Save and Go Back_ button. - -[[okta-application-config]] -=== Configure application.yml - -Now that you have created a new application with Okta, you need to configure the sample application to use the application for the _authentication flow_. To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - okta: <2> - client-id: okta-client-id - client-secret: okta-client-secret - provider: <3> - okta: - authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize - token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token - user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo - user-name-attribute: sub - jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, such as okta. -<3> `spring.security.oauth2.client.provider` is the base property prefix for OAuth Provider properties. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. -As well, replace `https://your-subdomain.oktapreview.com` in `authorization-uri`, `token-uri`, `user-info-uri` and `jwk-set-uri` with the sub-domain assigned to your account during the registration process. - -[[okta-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ login page, which displays a link for Okta. - -Click on the Okta link, and you are then redirected to Okta for authentication. - -After authenticating with your Okta account credentials, the OAuth Client retrieves your email address and basic profile information -from the https://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] and establishes an authenticated session. diff --git a/samples/boot/oauth2login/spring-security-samples-boot-oauth2login.gradle b/samples/boot/oauth2login/spring-security-samples-boot-oauth2login.gradle deleted file mode 100644 index ef3a4e27b5..0000000000 --- a/samples/boot/oauth2login/spring-security-samples-boot-oauth2login.gradle +++ /dev/null @@ -1,14 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-client') - compile project(':spring-security-oauth2-jose') - compile 'org.springframework.boot:spring-boot-starter-thymeleaf' - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' - - testCompile project(':spring-security-test') - testCompile 'net.sourceforge.htmlunit:htmlunit' - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/oauth2login/src/integration-test/java/sample/OAuth2LoginApplicationTests.java b/samples/boot/oauth2login/src/integration-test/java/sample/OAuth2LoginApplicationTests.java deleted file mode 100644 index 77867dbbc8..0000000000 --- a/samples/boot/oauth2login/src/integration-test/java/sample/OAuth2LoginApplicationTests.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.net.URI; -import java.net.URL; -import java.net.URLDecoder; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.WebResponse; -import com.gargoylesoftware.htmlunit.html.DomNodeList; -import com.gargoylesoftware.htmlunit.html.HtmlAnchor; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.http.HttpStatus; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; -import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; -import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; -import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; -import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter; -import org.springframework.security.oauth2.core.OAuth2AccessToken; -import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType; -import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; -import org.springframework.security.oauth2.core.user.DefaultOAuth2User; -import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; - -/** - * Integration tests for the OAuth 2.0 client filters {@link OAuth2AuthorizationRequestRedirectFilter} - * and {@link OAuth2LoginAuthenticationFilter}. These filters work together to realize - * OAuth 2.0 Login leveraging the Authorization Code Grant flow. - * - * @author Joe Grandja - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -public class OAuth2LoginApplicationTests { - private static final String AUTHORIZATION_BASE_URI = "/oauth2/authorization"; - private static final String AUTHORIZE_BASE_URL = "http://localhost:8080/login/oauth2/code"; - - @Autowired - private WebClient webClient; - - @Autowired - private MockMvc mvc; - - @Autowired - private ClientRegistrationRepository clientRegistrationRepository; - - @Before - public void setup() { - this.webClient.getCookieManager().clearCookies(); - } - - @Test - public void requestIndexPageWhenNotAuthenticatedThenDisplayLoginPage() throws Exception { - HtmlPage page = this.webClient.getPage("/"); - this.assertLoginPage(page); - } - - @Test - public void requestOtherPageWhenNotAuthenticatedThenDisplayLoginPage() throws Exception { - HtmlPage page = this.webClient.getPage("/other-page"); - this.assertLoginPage(page); - } - - @Test - public void requestAuthorizeGitHubClientWhenLinkClickedThenStatusRedirectForAuthorization() throws Exception { - HtmlPage page = this.webClient.getPage("/"); - - ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId("github"); - - HtmlAnchor clientAnchorElement = this.getClientAnchorElement(page, clientRegistration); - assertThat(clientAnchorElement).isNotNull(); - - WebResponse response = this.followLinkDisableRedirects(clientAnchorElement); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.MOVED_PERMANENTLY.value()); - - String authorizeRedirectUri = response.getResponseHeaderValue("Location"); - assertThat(authorizeRedirectUri).isNotNull(); - - UriComponents uriComponents = UriComponentsBuilder.fromUri(URI.create(authorizeRedirectUri)).build(); - - String requestUri = uriComponents.getScheme() + "://" + uriComponents.getHost() + uriComponents.getPath(); - assertThat(requestUri).isEqualTo(clientRegistration.getProviderDetails().getAuthorizationUri()); - - Map params = uriComponents.getQueryParams().toSingleValueMap(); - - assertThat(params.get(OAuth2ParameterNames.RESPONSE_TYPE)).isEqualTo(OAuth2AuthorizationResponseType.CODE.getValue()); - assertThat(params.get(OAuth2ParameterNames.CLIENT_ID)).isEqualTo(clientRegistration.getClientId()); - String redirectUri = AUTHORIZE_BASE_URL + "/" + clientRegistration.getRegistrationId(); - assertThat(URLDecoder.decode(params.get(OAuth2ParameterNames.REDIRECT_URI), "UTF-8")).isEqualTo(redirectUri); - assertThat(URLDecoder.decode(params.get(OAuth2ParameterNames.SCOPE), "UTF-8")) - .isEqualTo(clientRegistration.getScopes().stream().collect(Collectors.joining(" "))); - assertThat(params.get(OAuth2ParameterNames.STATE)).isNotNull(); - } - - @Test - public void requestAuthorizeClientWhenInvalidClientThenStatusInternalServerError() throws Exception { - HtmlPage page = this.webClient.getPage("/"); - - ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId("google"); - - HtmlAnchor clientAnchorElement = this.getClientAnchorElement(page, clientRegistration); - assertThat(clientAnchorElement).isNotNull(); - clientAnchorElement.setAttribute("href", clientAnchorElement.getHrefAttribute() + "-invalid"); - - WebResponse response = null; - try { - clientAnchorElement.click(); - } catch (FailingHttpStatusCodeException ex) { - response = ex.getResponse(); - } - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.value()); - } - - @Test - public void requestAuthorizationCodeGrantWhenValidAuthorizationResponseThenDisplayIndexPage() throws Exception { - HtmlPage page = this.webClient.getPage("/"); - - ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId("github"); - - HtmlAnchor clientAnchorElement = this.getClientAnchorElement(page, clientRegistration); - assertThat(clientAnchorElement).isNotNull(); - - WebResponse response = this.followLinkDisableRedirects(clientAnchorElement); - - UriComponents authorizeRequestUriComponents = UriComponentsBuilder.fromUri( - URI.create(response.getResponseHeaderValue("Location"))).build(); - - Map params = authorizeRequestUriComponents.getQueryParams().toSingleValueMap(); - String code = "auth-code"; - String state = URLDecoder.decode(params.get(OAuth2ParameterNames.STATE), "UTF-8"); - String redirectUri = URLDecoder.decode(params.get(OAuth2ParameterNames.REDIRECT_URI), "UTF-8"); - - String authorizationResponseUri = - UriComponentsBuilder.fromHttpUrl(redirectUri) - .queryParam(OAuth2ParameterNames.CODE, code) - .queryParam(OAuth2ParameterNames.STATE, state) - .build().encode().toUriString(); - - page = this.webClient.getPage(new URL(authorizationResponseUri)); - this.assertIndexPage(page); - } - - @Test - public void requestAuthorizationCodeGrantWhenNoMatchingAuthorizationRequestThenDisplayLoginPageWithError() throws Exception { - HtmlPage page = this.webClient.getPage("/"); - URL loginPageUrl = page.getBaseURL(); - URL loginErrorPageUrl = new URL(loginPageUrl.toString() + "?error"); - - ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId("google"); - - String code = "auth-code"; - String state = "state"; - String redirectUri = AUTHORIZE_BASE_URL + "/" + clientRegistration.getRegistrationId(); - - String authorizationResponseUri = - UriComponentsBuilder.fromHttpUrl(redirectUri) - .queryParam(OAuth2ParameterNames.CODE, code) - .queryParam(OAuth2ParameterNames.STATE, state) - .build().encode().toUriString(); - - // Clear session cookie will ensure the 'session-saved' - // Authorization Request (from previous request) is not found - this.webClient.getCookieManager().clearCookies(); - - page = this.webClient.getPage(new URL(authorizationResponseUri)); - assertThat(page.getBaseURL()).isEqualTo(loginErrorPageUrl); - - HtmlElement errorElement = page.getBody().getFirstByXPath("div"); - assertThat(errorElement).isNotNull(); - assertThat(errorElement.asText()).contains("authorization_request_not_found"); - } - - @Test - public void requestAuthorizationCodeGrantWhenInvalidStateParamThenDisplayLoginPageWithError() throws Exception { - HtmlPage page = this.webClient.getPage("/"); - URL loginPageUrl = page.getBaseURL(); - URL loginErrorPageUrl = new URL(loginPageUrl.toString() + "?error"); - - ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId("google"); - - HtmlAnchor clientAnchorElement = this.getClientAnchorElement(page, clientRegistration); - assertThat(clientAnchorElement).isNotNull(); - this.followLinkDisableRedirects(clientAnchorElement); - - String code = "auth-code"; - String state = "invalid-state"; - String redirectUri = AUTHORIZE_BASE_URL + "/" + clientRegistration.getRegistrationId(); - - String authorizationResponseUri = - UriComponentsBuilder.fromHttpUrl(redirectUri) - .queryParam(OAuth2ParameterNames.CODE, code) - .queryParam(OAuth2ParameterNames.STATE, state) - .build().encode().toUriString(); - - page = this.webClient.getPage(new URL(authorizationResponseUri)); - assertThat(page.getBaseURL()).isEqualTo(loginErrorPageUrl); - - HtmlElement errorElement = page.getBody().getFirstByXPath("div"); - assertThat(errorElement).isNotNull(); - assertThat(errorElement.asText()).contains("authorization_request_not_found"); - } - - @Test - public void requestWhenMockOAuth2LoginThenIndex() throws Exception { - ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId("github"); - this.mvc.perform(get("/").with(oauth2Login().clientRegistration(clientRegistration))) - .andExpect(model().attribute("userName", "user")) - .andExpect(model().attribute("clientName", "GitHub")) - .andExpect(model().attribute("userAttributes", Collections.singletonMap("sub", "user"))); - } - - private void assertLoginPage(HtmlPage page) { - assertThat(page.getTitleText()).isEqualTo("Please sign in"); - - int expectedClients = 4; - - List clientAnchorElements = page.getAnchors(); - assertThat(clientAnchorElements.size()).isEqualTo(expectedClients); - - ClientRegistration googleClientRegistration = this.clientRegistrationRepository.findByRegistrationId("google"); - ClientRegistration githubClientRegistration = this.clientRegistrationRepository.findByRegistrationId("github"); - ClientRegistration facebookClientRegistration = this.clientRegistrationRepository.findByRegistrationId("facebook"); - ClientRegistration oktaClientRegistration = this.clientRegistrationRepository.findByRegistrationId("okta"); - - String baseAuthorizeUri = AUTHORIZATION_BASE_URI + "/"; - String googleClientAuthorizeUri = baseAuthorizeUri + googleClientRegistration.getRegistrationId(); - String githubClientAuthorizeUri = baseAuthorizeUri + githubClientRegistration.getRegistrationId(); - String facebookClientAuthorizeUri = baseAuthorizeUri + facebookClientRegistration.getRegistrationId(); - String oktaClientAuthorizeUri = baseAuthorizeUri + oktaClientRegistration.getRegistrationId(); - - for (int i=0; i divElements = page.getBody().getElementsByTagName("div"); - assertThat(divElements.get(1).asText()).contains("User: joeg@springsecurity.io"); - assertThat(divElements.get(4).asText()).contains("You are successfully logged in joeg@springsecurity.io"); - } - - private HtmlAnchor getClientAnchorElement(HtmlPage page, ClientRegistration clientRegistration) { - Optional clientAnchorElement = page.getAnchors().stream() - .filter((e) -> e.asText().equals(clientRegistration.getClientName())).findFirst(); - - return (clientAnchorElement.orElse(null)); - } - - private WebResponse followLinkDisableRedirects(HtmlAnchor anchorElement) throws Exception { - WebResponse response = null; - try { - // Disable the automatic redirection (which will trigger - // an exception) so that we can capture the response - this.webClient.getOptions().setRedirectEnabled(false); - anchorElement.click(); - } catch (FailingHttpStatusCodeException ex) { - response = ex.getResponse(); - this.webClient.getOptions().setRedirectEnabled(true); - } - return response; - } - - @EnableWebSecurity - @TestConfiguration - public static class SecurityTestConfig extends WebSecurityConfigurerAdapter { - - // @formatter:off - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests((authorizeRequests) -> - authorizeRequests - .anyRequest().authenticated() - ) - .oauth2Login((oauth2Login) -> - oauth2Login - .tokenEndpoint((tokenEndpoint) -> - tokenEndpoint - .accessTokenResponseClient(this.mockAccessTokenResponseClient()) - ) - .userInfoEndpoint((userInfoEndpoint) -> - userInfoEndpoint - .userService(this.mockUserService()) - ) - ); - } - // @formatter:on - - private OAuth2AccessTokenResponseClient mockAccessTokenResponseClient() { - OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("access-token-1234") - .tokenType(OAuth2AccessToken.TokenType.BEARER) - .expiresIn(60 * 1000) - .build(); - - OAuth2AccessTokenResponseClient tokenResponseClient = mock(OAuth2AccessTokenResponseClient.class); - when(tokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse); - return tokenResponseClient; - } - - private OAuth2UserService mockUserService() { - Map attributes = new HashMap<>(); - attributes.put("id", "joeg"); - attributes.put("first-name", "Joe"); - attributes.put("last-name", "Grandja"); - attributes.put("email", "joeg@springsecurity.io"); - - GrantedAuthority authority = new OAuth2UserAuthority(attributes); - Set authorities = new HashSet<>(); - authorities.add(authority); - - DefaultOAuth2User user = new DefaultOAuth2User(authorities, attributes, "email"); - - OAuth2UserService userService = mock(OAuth2UserService.class); - when(userService.loadUser(any())).thenReturn(user); - return userService; - } - } -} diff --git a/samples/boot/oauth2login/src/main/java/sample/OAuth2LoginApplication.java b/samples/boot/oauth2login/src/main/java/sample/OAuth2LoginApplication.java deleted file mode 100644 index dc69b3f9ec..0000000000 --- a/samples/boot/oauth2login/src/main/java/sample/OAuth2LoginApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Joe Grandja - */ -@SpringBootApplication -public class OAuth2LoginApplication { - - public static void main(String[] args) { - SpringApplication.run(OAuth2LoginApplication.class, args); - } -} diff --git a/samples/boot/oauth2login/src/main/java/sample/web/OAuth2LoginController.java b/samples/boot/oauth2login/src/main/java/sample/web/OAuth2LoginController.java deleted file mode 100644 index fa46a60ad7..0000000000 --- a/samples/boot/oauth2login/src/main/java/sample/web/OAuth2LoginController.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.web; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; -import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; - -/** - * @author Joe Grandja - * @author Rob Winch - */ -@Controller -public class OAuth2LoginController { - - @GetMapping("/") - public String index(Model model, - @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient, - @AuthenticationPrincipal OAuth2User oauth2User) { - model.addAttribute("userName", oauth2User.getName()); - model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName()); - model.addAttribute("userAttributes", oauth2User.getAttributes()); - return "index"; - } -} diff --git a/samples/boot/oauth2login/src/main/resources/application.yml b/samples/boot/oauth2login/src/main/resources/application.yml deleted file mode 100644 index 73b08fbd83..0000000000 --- a/samples/boot/oauth2login/src/main/resources/application.yml +++ /dev/null @@ -1,35 +0,0 @@ -server: - port: 8080 - -logging: - level: - root: INFO - org.springframework.web: INFO - org.springframework.security: INFO -# org.springframework.boot.autoconfigure: DEBUG - -spring: - thymeleaf: - cache: false - security: - oauth2: - client: - registration: - google: - client-id: your-app-client-id - client-secret: your-app-client-secret - github: - client-id: your-app-client-id - client-secret: your-app-client-secret - facebook: - client-id: your-app-client-id - client-secret: your-app-client-secret - okta: - client-id: your-app-client-id - client-secret: your-app-client-secret - provider: - okta: - authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize - token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token - user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo - jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys diff --git a/samples/boot/oauth2login/src/main/resources/templates/index.html b/samples/boot/oauth2login/src/main/resources/templates/index.html deleted file mode 100644 index 629d8ac8ee..0000000000 --- a/samples/boot/oauth2login/src/main/resources/templates/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - Spring Security - OAuth 2.0 Login - - - -
-
- User: -
-
 
-
-
- -
-
-
-

OAuth 2.0 Login with Spring Security

-
- You are successfully logged in - via the OAuth 2.0 Client -
-
 
-
- User Attributes: -
    -
  • - : -
  • -
-
- - diff --git a/samples/boot/oauth2login/src/test/java/sample/web/OAuth2LoginControllerTests.java b/samples/boot/oauth2login/src/test/java/sample/web/OAuth2LoginControllerTests.java deleted file mode 100644 index 6a3af42ff7..0000000000 --- a/samples/boot/oauth2login/src/test/java/sample/web/OAuth2LoginControllerTests.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.web; - -import java.util.Collections; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.core.AuthorizationGrantType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; - -/** - * Tests for {@link OAuth2LoginController} - * - * @author Josh Cummings - */ -@RunWith(SpringRunner.class) -@WebMvcTest(OAuth2LoginController.class) -public class OAuth2LoginControllerTests { - - @Autowired - MockMvc mvc; - - @Test - public void rootWhenAuthenticatedReturnsUserAndClient() throws Exception { - this.mvc.perform(get("/").with(oauth2Login())) - .andExpect(model().attribute("userName", "user")) - .andExpect(model().attribute("clientName", "test")) - .andExpect(model().attribute("userAttributes", Collections.singletonMap("sub", "user"))); - } - - @Test - public void rootWhenOverridingClientRegistrationReturnsAccordingly() throws Exception { - ClientRegistration clientRegistration = ClientRegistration.withRegistrationId("test") - .authorizationGrantType(AuthorizationGrantType.PASSWORD) - .clientId("my-client-id") - .clientName("my-client-name") - .tokenUri("https://token-uri.example.org") - .build(); - - this.mvc.perform(get("/").with(oauth2Login() - .clientRegistration(clientRegistration) - .attributes((a) -> a.put("sub", "spring-security")))) - .andExpect(model().attribute("userName", "spring-security")) - .andExpect(model().attribute("clientName", "my-client-name")) - .andExpect(model().attribute("userAttributes", Collections.singletonMap("sub", "spring-security"))); - } -} diff --git a/samples/boot/oauth2resourceserver-jwe/README.adoc b/samples/boot/oauth2resourceserver-jwe/README.adoc deleted file mode 100644 index 84c64f6f58..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/README.adoc +++ /dev/null @@ -1,119 +0,0 @@ -= OAuth 2.0 Resource Server Sample - -This sample demonstrates integrating Resource Server with a mock Authorization Server, though it can be modified to integrate -with your favorite Authorization Server. This resource server is configured to accept JWE-encrypted tokens. - -With it, you can run the integration tests or run the application as a stand-alone service to explore how you can -secure your own service with OAuth 2.0 Bearer Tokens using Spring Security. - -== 1. Running the tests - -To run the tests, do: - -```bash -./gradlew integrationTest -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplicationTests` from there. - -=== What is it doing? - -By default, the tests are pointing at a mock Authorization Server instance. - -The tests are configured with a set of hard-coded tokens originally obtained from the mock Authorization Server, -and each makes a query to the Resource Server with their corresponding token. - -The Resource Server decrypts the token and subsquently verifies it with the Authorization Server and authorizes the request, returning the phrase - -```bash -Hello, subject! -``` - -where "subject" is the value of the `sub` field in the JWT returned by the Authorization Server. - -== 2. Running the app - -To run as a stand-alone application, do: - -```bash -./gradlew bootRun -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplication` from there. - -Once it is up, you can use the following token: - -```bash -export TOKEN=eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.IyeWtsTonaiWJdoT13B0M7gpqVxAirVGlfqFI4TOmTRcVHICs_ESezS7fa0ODS9XYdwklTtG7hH39yeeMzr2Zo1Ghh-m36fdoqQrV1Do04rUvuTjqbgyNffeZEGB6rquJ-cyAVjp_Oljy10-Bbnw7CeVGwNBSVo9UCB5j49OlNWhLxFpYARFmOlYpXj-s4Q4JiqV6EvjDAYeohAR4QQmND3qoxR-s2I6SLcIho0sSSpUlhrRiqu2uvWefHDcZJdW2WYWnxLHxhzNu3CfnLiqhhaA_YA_iWXR9FYnPDCf_4q3FgSXcgttXzomFKAx5DwnE_dXvsCvpWxslZMU1UIiLA.MHOrrza2GQ9_5PIv.zU4tfhxT6apWBC3stBwQmGlCQBltWVQe4dFIykybWWBFqxo1bf2BZ37twzoEIFXG9jSYEMH4mvBXPWSvn66t-_jnqLnKTJst2plBjhagGCAoLNWXVKeYNp67o-lKOD_JJQFqsRw4oE05VSgRr14MZeaUBFcU3A_kKxMXOu899DKfXBGJvj75H7lDyd8RUXTb-OSWWfUiJc6Y5AUy1zCZCN9yfDsCXt9heTsZANy92Oou9sMFaXkYzyums5OtkBtLFzyuNMEoNioRehTV-FTuL8tDRB1mNhHObwsBfFbR6M1jJK37pHUXGtko-yZ6NGwxyLtwGh4uU2jzE614rQzuzR8aHaHxOkUs1pBTZ8AcRt41snByOe-KU0adthHxedobFiQQBoQ05DgSU7DO6hsK0uVBDF3eG2KjH4L2lZy-WugloLHhdguUoO9F0zUx15-XZO4EVzmhy8xfH2tSXz98eKzz9Dv0DdGnrBL9cK2MM88N1zoq5u4NdlnE12HvuesB7GKdMwZx1-gTw_pzP81TzcctJWl6ETK09Uc.jk0O8qc4Fvip856stDz05Q -``` - -And then make this request: - -```bash -curl -H "Authorization: Bearer $TOKEN" localhost:8080 -``` - -Which will respond with the phrase: - -```bash -Hello, subject! -``` - -where `subject` is the value of the `sub` field in the JWT returned by the Authorization Server. - -Or this: - -```bash -export TOKEN=eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.CRBAEgvQhpB6pPQhpkTAKpsDai1FDcvkDSRig1R3OI-g18JdTe-qDhzWwP-hV3aCwFwHxQ_g8Z8OIZvhyKpQaPwBb72UeLqqhzSIkm0gEsmmjYg1vEGOrDH5_Fqlm0LnAnXTmsbOIWYIj11ZuenI2lEmMCkVwqth0RlzakdcHRXiuDTEln_trhZpE2j80X-9rS2gZy9Raa9VLir3-F3wC0GKPEL6e3x1OygC03ix9uyXS3vpTsU9zlgoYADZyaLeOF1mCG4mQhvXs7IPmPbwNsElJwKh0xSQCHvNOQShprlvd3cHiUFKYw9fXphY1O-AUYcRzHk4DjoBdkGNQMy_Kw.KtC_z674rYBtDgkN.e8QU50Iq1JHkn-1USSxpjEkbrukb4cobvlQRK40iXGAKVIuOod4bSq5fDpIAPHugqIf-_zGsvr-2OCOdzhtBikL46wU7UdZppxPWtk-X6kl33zH_XObRMaGfe-hLxt3RPxRVn7I1Hp6tGW1Rkxyf_ESq4XlcbbrkhDoIz_G_LKXJhvQ-xahW2e0AUc7RZSucns4XUeq9xX_dd7Ht-o1TmQI9WFoFc1l7oh9GtQ6GZMsghnZ1VrbIS2L7jSYiSsD2JqSv1LLtOGj_FBA0ufhqM3LloGiwflEwAryMD10oNb73WonKEycEj1rBsTIKW7SHkI-VkrQA4-8N-aLWgHwDnzyPZmyNyKpqUMvhjIE_0w6oqU4HpN7J5nfBEIAtpPZ_pDkwAdxCQ7JV3zfiUnF7ZQ3q1PnSId315si02ZN9-wRSrMHcHnboQN1Hs4xCAfGyClVyLpCzfa_fAehjt6v1DjgjbzwSjr_LdNmWTvXYBhNO8Jq9Vb7axksrdwksD3pYNMY8cRZxP-LO0V5Sv1_kT_Hf2yLo2iTwB8n8szzGrJ4QQLb5Znu7Sv-M2x52cnIDMiorP3LNpFk.G85FuMSm-8bGumFAStiFQA - -curl -H "Authorization: Bearer $TOKEN" localhost:8080/message -``` - -Will respond with: - -```bash -secret message -``` - -== 2. Testing against other Authorization Servers - -_In order to use this sample, your Authorization Server must encrypt using the public key available in the sample. -Also it must support JWTs that either use the "scope" or "scp" attribute._ - -To change the sample to point at your Authorization Server, simply find this property in the `application.yml`: - -```yaml -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json -``` - -And change the property to your Authorization Server's JWK set endpoint: - -```yaml -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: https://localhost:9031/pf/JWKS -``` - -If your Authorization Server does not support RSA_OAEP_256 or AESGCM, then you can change these values in `OAuth2ResourceServerSecurityConfiguration`: - -```java - -``` - -And then you can run the app the same as before: - -```bash -./gradlew bootRun -``` - -Make sure to obtain valid tokens from your Authorization Server in order to play with the sample Resource Server. -To use the `/` endpoint, any valid token from your Authorization Server will do. -To use the `/message` endpoint, the token should have the `message:read` scope. diff --git a/samples/boot/oauth2resourceserver-jwe/spring-security-samples-boot-oauth2resourceserver-jwe.gradle b/samples/boot/oauth2resourceserver-jwe/spring-security-samples-boot-oauth2resourceserver-jwe.gradle deleted file mode 100644 index 2135bb0af6..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/spring-security-samples-boot-oauth2resourceserver-jwe.gradle +++ /dev/null @@ -1,13 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-jose') - compile project(':spring-security-oauth2-resource-server') - - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'com.squareup.okhttp3:mockwebserver' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/oauth2resourceserver-jwe/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java b/samples/boot/oauth2resourceserver-jwe/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java deleted file mode 100644 index cd25346ce8..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.RequestPostProcessor; - -import static org.hamcrest.Matchers.containsString; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * Integration tests for {@link OAuth2ResourceServerApplication} - * - * @author Josh Cummings - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -@ActiveProfiles("test") -public class OAuth2ResourceServerApplicationITests { - - String noScopesToken = "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.IyeWtsTonaiWJdoT13B0M7gpqVxAirVGlfqFI4TOmTRcVHICs_ESezS7fa0ODS9XYdwklTtG7hH39yeeMzr2Zo1Ghh-m36fdoqQrV1Do04rUvuTjqbgyNffeZEGB6rquJ-cyAVjp_Oljy10-Bbnw7CeVGwNBSVo9UCB5j49OlNWhLxFpYARFmOlYpXj-s4Q4JiqV6EvjDAYeohAR4QQmND3qoxR-s2I6SLcIho0sSSpUlhrRiqu2uvWefHDcZJdW2WYWnxLHxhzNu3CfnLiqhhaA_YA_iWXR9FYnPDCf_4q3FgSXcgttXzomFKAx5DwnE_dXvsCvpWxslZMU1UIiLA.MHOrrza2GQ9_5PIv.zU4tfhxT6apWBC3stBwQmGlCQBltWVQe4dFIykybWWBFqxo1bf2BZ37twzoEIFXG9jSYEMH4mvBXPWSvn66t-_jnqLnKTJst2plBjhagGCAoLNWXVKeYNp67o-lKOD_JJQFqsRw4oE05VSgRr14MZeaUBFcU3A_kKxMXOu899DKfXBGJvj75H7lDyd8RUXTb-OSWWfUiJc6Y5AUy1zCZCN9yfDsCXt9heTsZANy92Oou9sMFaXkYzyums5OtkBtLFzyuNMEoNioRehTV-FTuL8tDRB1mNhHObwsBfFbR6M1jJK37pHUXGtko-yZ6NGwxyLtwGh4uU2jzE614rQzuzR8aHaHxOkUs1pBTZ8AcRt41snByOe-KU0adthHxedobFiQQBoQ05DgSU7DO6hsK0uVBDF3eG2KjH4L2lZy-WugloLHhdguUoO9F0zUx15-XZO4EVzmhy8xfH2tSXz98eKzz9Dv0DdGnrBL9cK2MM88N1zoq5u4NdlnE12HvuesB7GKdMwZx1-gTw_pzP81TzcctJWl6ETK09Uc.jk0O8qc4Fvip856stDz05Q"; - String messageReadToken = "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.CRBAEgvQhpB6pPQhpkTAKpsDai1FDcvkDSRig1R3OI-g18JdTe-qDhzWwP-hV3aCwFwHxQ_g8Z8OIZvhyKpQaPwBb72UeLqqhzSIkm0gEsmmjYg1vEGOrDH5_Fqlm0LnAnXTmsbOIWYIj11ZuenI2lEmMCkVwqth0RlzakdcHRXiuDTEln_trhZpE2j80X-9rS2gZy9Raa9VLir3-F3wC0GKPEL6e3x1OygC03ix9uyXS3vpTsU9zlgoYADZyaLeOF1mCG4mQhvXs7IPmPbwNsElJwKh0xSQCHvNOQShprlvd3cHiUFKYw9fXphY1O-AUYcRzHk4DjoBdkGNQMy_Kw.KtC_z674rYBtDgkN.e8QU50Iq1JHkn-1USSxpjEkbrukb4cobvlQRK40iXGAKVIuOod4bSq5fDpIAPHugqIf-_zGsvr-2OCOdzhtBikL46wU7UdZppxPWtk-X6kl33zH_XObRMaGfe-hLxt3RPxRVn7I1Hp6tGW1Rkxyf_ESq4XlcbbrkhDoIz_G_LKXJhvQ-xahW2e0AUc7RZSucns4XUeq9xX_dd7Ht-o1TmQI9WFoFc1l7oh9GtQ6GZMsghnZ1VrbIS2L7jSYiSsD2JqSv1LLtOGj_FBA0ufhqM3LloGiwflEwAryMD10oNb73WonKEycEj1rBsTIKW7SHkI-VkrQA4-8N-aLWgHwDnzyPZmyNyKpqUMvhjIE_0w6oqU4HpN7J5nfBEIAtpPZ_pDkwAdxCQ7JV3zfiUnF7ZQ3q1PnSId315si02ZN9-wRSrMHcHnboQN1Hs4xCAfGyClVyLpCzfa_fAehjt6v1DjgjbzwSjr_LdNmWTvXYBhNO8Jq9Vb7axksrdwksD3pYNMY8cRZxP-LO0V5Sv1_kT_Hf2yLo2iTwB8n8szzGrJ4QQLb5Znu7Sv-M2x52cnIDMiorP3LNpFk.G85FuMSm-8bGumFAStiFQA"; - - @Autowired - MockMvc mvc; - - @Test - public void performWhenValidBearerTokenThenAllows() - throws Exception { - - this.mvc.perform(get("/").with(bearerToken(this.noScopesToken))) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("Hello, subject!"))); - } - - @Test - public void performWhenValidBearerTokenThenScopedRequestsAlsoWork() - throws Exception { - - this.mvc.perform(get("/message").with(bearerToken(this.messageReadToken))) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("secret message"))); - } - - @Test - public void performWhenInsufficientlyScopedBearerTokenThenDeniesScopedMethodAccess() - throws Exception { - - this.mvc.perform(get("/message").with(bearerToken(this.noScopesToken))) - .andExpect(status().isForbidden()) - .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, - containsString("Bearer error=\"insufficient_scope\""))); - } - - private static class BearerTokenRequestPostProcessor implements RequestPostProcessor { - private String token; - - BearerTokenRequestPostProcessor(String token) { - this.token = token; - } - - @Override - public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { - request.addHeader("Authorization", "Bearer " + this.token); - return request; - } - } - - private static BearerTokenRequestPostProcessor bearerToken(String token) { - return new BearerTokenRequestPostProcessor(token); - } -} diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java b/samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java deleted file mode 100644 index 62f91d1a1f..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.boot.SpringApplication; -import org.springframework.core.env.ConfigurableEnvironment; - -/** - * @author Rob Winch - */ -public class MockWebServerEnvironmentPostProcessor - implements EnvironmentPostProcessor, DisposableBean { - - private final MockWebServerPropertySource propertySource = new MockWebServerPropertySource(); - - @Override - public void postProcessEnvironment(ConfigurableEnvironment environment, - SpringApplication application) { - environment.getPropertySources().addFirst(this.propertySource); - } - - @Override - public void destroy() throws Exception { - this.propertySource.destroy(); - } -} diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java b/samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java deleted file mode 100644 index 5e9df1d836..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import java.io.IOException; - -import okhttp3.mockwebserver.Dispatcher; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.core.env.PropertySource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - -/** - * @author Rob Winch - */ -public class MockWebServerPropertySource extends PropertySource implements - DisposableBean { - - private static final MockResponse JWKS_RESPONSE = response( - "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"n\":\"i7H90yfquGVhXxekdzXkMaxlIg67Q_ofd7iuFHtgeUx-Iye2QjukuULhl774oITYnZIZsh2UHxRYG8nFypcYZfHJMQes_OYFTkTvRroKll5p3wxSkhpARbkEPFMyMJ5WIm3MeNO2ermMhDWVVeI2xQH-tW6w-C6b5d_F6lrIwCnpZwSv6PQ3kef-rcObp_PZANIo232bvpwyC6uW1W2kpjAvYJhQ8NrkG2oO0ynqEJW2UyoCWRdsT2BLZcFMAcxG3Iw9b9__IbvNoUBwr596JYfzrX0atiKyk4Yg8dJ1wBjHFN2fkHTlzn6HDwTJkj4VNDQvKu4P2zhKn1gmWuxhuQ\"}]}", - 200 - ); - - private static final MockResponse NOT_FOUND_RESPONSE = response( - "{ \"message\" : \"This mock authorization server responds to just one request: GET /.well-known/jwks.json.\" }", - 404 - ); - - /** - * Name of the random {@link PropertySource}. - */ - public static final String MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME = "mockwebserver"; - - private static final String NAME = "mockwebserver.url"; - - private static final Log logger = LogFactory.getLog(MockWebServerPropertySource.class); - - private boolean started; - - public MockWebServerPropertySource() { - super(MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME, new MockWebServer()); - } - - @Override - public Object getProperty(String name) { - if (!name.equals(NAME)) { - return null; - } - if (logger.isTraceEnabled()) { - logger.trace("Looking up the url for '" + name + "'"); - } - String url = getUrl(); - return url; - } - - @Override - public void destroy() throws Exception { - getSource().shutdown(); - } - - /** - * Get's the URL (i.e. "http://localhost:123456") - * @return - */ - private String getUrl() { - MockWebServer mockWebServer = getSource(); - if (!this.started) { - intializeMockWebServer(mockWebServer); - } - String url = mockWebServer.url("").url().toExternalForm(); - return url.substring(0, url.length() - 1); - } - - private void intializeMockWebServer(MockWebServer mockWebServer) { - Dispatcher dispatcher = new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest request) { - if ("/.well-known/jwks.json".equals(request.getPath())) { - return JWKS_RESPONSE; - } - - return NOT_FOUND_RESPONSE; - } - }; - - mockWebServer.setDispatcher(dispatcher); - try { - mockWebServer.start(); - this.started = true; - } catch (IOException e) { - throw new RuntimeException("Could not start " + mockWebServer, e); - } - } - - private static MockResponse response(String body, int status) { - return new MockResponse() - .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .setResponseCode(status) - .setBody(body); - } - -} diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/package-info.java b/samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/package-info.java deleted file mode 100644 index 0226037822..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/java/org/springframework/boot/env/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This provides integration of a {@link okhttp3.mockwebserver.MockWebServer} and the - * {@link org.springframework.core.env.Environment} - * @author Rob Winch - */ -package org.springframework.boot.env; diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerApplication.java b/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerApplication.java deleted file mode 100644 index a0841c00f3..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Josh Cummings - */ -@SpringBootApplication -public class OAuth2ResourceServerApplication { - - public static void main(String[] args) { - SpringApplication.run(OAuth2ResourceServerApplication.class, args); - } -} diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerController.java b/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerController.java deleted file mode 100644 index f0bcdbe64f..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerController.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Josh Cummings - */ -@RestController -public class OAuth2ResourceServerController { - - @GetMapping("/") - public String index(@AuthenticationPrincipal Jwt jwt) { - return String.format("Hello, %s!", jwt.getSubject()); - } - - @GetMapping("/message") - public String message() { - return "secret message"; - } -} diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java deleted file mode 100644 index dfe4135d4b..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.net.URL; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPrivateKey; - -import com.nimbusds.jose.EncryptionMethod; -import com.nimbusds.jose.JWEAlgorithm; -import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jose.jwk.JWKSet; -import com.nimbusds.jose.jwk.KeyUse; -import com.nimbusds.jose.jwk.RSAKey; -import com.nimbusds.jose.jwk.source.ImmutableJWKSet; -import com.nimbusds.jose.jwk.source.JWKSource; -import com.nimbusds.jose.jwk.source.RemoteJWKSet; -import com.nimbusds.jose.proc.JWEDecryptionKeySelector; -import com.nimbusds.jose.proc.JWEKeySelector; -import com.nimbusds.jose.proc.JWSKeySelector; -import com.nimbusds.jose.proc.JWSVerificationKeySelector; -import com.nimbusds.jose.proc.SecurityContext; -import com.nimbusds.jose.util.Base64URL; -import com.nimbusds.jwt.proc.ConfigurableJWTProcessor; -import com.nimbusds.jwt.proc.DefaultJWTProcessor; -import com.nimbusds.jwt.proc.JWTProcessor; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; - -import static org.springframework.security.config.Customizer.withDefaults; - -/** - * @author Josh Cummings - */ -@EnableWebSecurity -public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter { - - private final JWSAlgorithm jwsAlgorithm = JWSAlgorithm.RS256; - private final JWEAlgorithm jweAlgorithm = JWEAlgorithm.RSA_OAEP_256; - private final EncryptionMethod encryptionMethod = EncryptionMethod.A256GCM; - - @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}") - URL jwkSetUri; - - @Value("${sample.jwe-key-value}") - RSAPrivateKey key; - - @Override - protected void configure(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeRequests((authorizeRequests) -> - authorizeRequests - .antMatchers("/message/**").hasAuthority("SCOPE_message:read") - .anyRequest().authenticated() - ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .jwt(withDefaults()) - ); - // @formatter:on - } - - @Bean - JwtDecoder jwtDecoder() { - return new NimbusJwtDecoder(jwtProcessor()); - } - - private JWTProcessor jwtProcessor() { - JWKSource jwsJwkSource = new RemoteJWKSet<>(this.jwkSetUri); - JWSKeySelector jwsKeySelector = - new JWSVerificationKeySelector<>(this.jwsAlgorithm, jwsJwkSource); - - JWKSource jweJwkSource = new ImmutableJWKSet<>(new JWKSet(rsaKey())); - JWEKeySelector jweKeySelector = - new JWEDecryptionKeySelector<>(this.jweAlgorithm, this.encryptionMethod, jweJwkSource); - - ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor<>(); - jwtProcessor.setJWSKeySelector(jwsKeySelector); - jwtProcessor.setJWEKeySelector(jweKeySelector); - - return jwtProcessor; - } - - private RSAKey rsaKey() { - RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey) this.key; - Base64URL n = Base64URL.encode(crtKey.getModulus()); - Base64URL e = Base64URL.encode(crtKey.getPublicExponent()); - return new RSAKey.Builder(n, e) - .privateKey(this.key) - .keyUse(KeyUse.ENCRYPTION) - .build(); - } -} diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/resources/META-INF/spring.factories b/samples/boot/oauth2resourceserver-jwe/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 37b447c970..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=org.springframework.boot.env.MockWebServerEnvironmentPostProcessor diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/resources/application.yml b/samples/boot/oauth2resourceserver-jwe/src/main/resources/application.yml deleted file mode 100644 index 8573fda8f6..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/resources/application.yml +++ /dev/null @@ -1,9 +0,0 @@ -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json - -sample: - jwe-key-value: classpath:simple.priv diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/resources/simple.priv b/samples/boot/oauth2resourceserver-jwe/src/main/resources/simple.priv deleted file mode 100644 index 53510079ac..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/resources/simple.priv +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDcWWomvlNGyQhA -iB0TcN3sP2VuhZ1xNRPxr58lHswC9Cbtdc2hiSbe/sxAvU1i0O8vaXwICdzRZ1JM -g1TohG9zkqqjZDhyw1f1Ic6YR/OhE6NCpqERy97WMFeW6gJd1i5inHj/W19GAbqK -LhSHGHqIjyo0wlBf58t+qFt9h/EFBVE/LAGQBsg/jHUQCxsLoVI2aSELGIw2oSDF -oiljwLaQl0n9khX5ZbiegN3OkqodzCYHwWyu6aVVj8M1W9RIMiKmKr09s/gf31Nc -3WjvjqhFo1rTuurWGgKAxJLL7zlJqAKjGWbIT4P6h/1Kwxjw6X23St3OmhsG6HIn -+jl1++MrAgMBAAECggEBAMf820wop3pyUOwI3aLcaH7YFx5VZMzvqJdNlvpg1jbE -E2Sn66b1zPLNfOIxLcBG8x8r9Ody1Bi2Vsqc0/5o3KKfdgHvnxAB3Z3dPh2WCDek -lCOVClEVoLzziTuuTdGO5/CWJXdWHcVzIjPxmK34eJXioiLaTYqN3XKqKMdpD0ZG -mtNTGvGf+9fQ4i94t0WqIxpMpGt7NM4RHy3+Onggev0zLiDANC23mWrTsUgect/7 -62TYg8g1bKwLAb9wCBT+BiOuCc2wrArRLOJgUkj/F4/gtrR9ima34SvWUyoUaKA0 -bi4YBX9l8oJwFGHbU9uFGEMnH0T/V0KtIB7qetReywkCgYEA9cFyfBIQrYISV/OA -+Z0bo3vh2aL0QgKrSXZ924cLt7itQAHNZ2ya+e3JRlTczi5mnWfjPWZ6eJB/8MlH -Gpn12o/POEkU+XjZZSPe1RWGt5g0S3lWqyx9toCS9ACXcN9tGbaqcFSVI73zVTRA -8J9grR0fbGn7jaTlTX2tnlOTQ60CgYEA5YjYpEq4L8UUMFkuj+BsS3u0oEBnzuHd -I9LEHmN+CMPosvabQu5wkJXLuqo2TxRnAznsA8R3pCLkdPGoWMCiWRAsCn979TdY -QbqO2qvBAD2Q19GtY7lIu6C35/enQWzJUMQE3WW0OvjLzZ0l/9mA2FBRR+3F9A1d -rBdnmv0c3TcCgYEAi2i+ggVZcqPbtgrLOk5WVGo9F1GqUBvlgNn30WWNTx4zIaEk -HSxtyaOLTxtq2odV7Kr3LGiKxwPpn/T+Ief+oIp92YcTn+VfJVGw4Z3BezqbR8lA -Uf/+HF5ZfpMrVXtZD4Igs3I33Duv4sCuqhEvLWTc44pHifVloozNxYfRfU0CgYBN -HXa7a6cJ1Yp829l62QlJKtx6Ymj95oAnQu5Ez2ROiZMqXRO4nucOjGUP55Orac1a -FiGm+mC/skFS0MWgW8evaHGDbWU180wheQ35hW6oKAb7myRHtr4q20ouEtQMdQIF -snV39G1iyqeeAsf7dxWElydXpRi2b68i3BIgzhzebQKBgQCdUQuTsqV9y/JFpu6H -c5TVvhG/ubfBspI5DhQqIGijnVBzFT//UfIYMSKJo75qqBEyP2EJSmCsunWsAFsM -TszuiGTkrKcZy9G0wJqPztZZl2F2+bJgnA6nBEV7g5PA4Af+QSmaIhRwqGDAuROR -47jndeyIaMTNETEmOnms+as17g== ------END PRIVATE KEY----- \ No newline at end of file diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/resources/simple.pub b/samples/boot/oauth2resourceserver-jwe/src/main/resources/simple.pub deleted file mode 100644 index 0b2ee7b336..0000000000 --- a/samples/boot/oauth2resourceserver-jwe/src/main/resources/simple.pub +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FlqJr5TRskIQIgdE3Dd -7D9lboWdcTUT8a+fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRv -c5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4/1tfRgG6ii4Uhxh6 -iI8qNMJQX+fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2 -kJdJ/ZIV+WW4noDdzpKqHcwmB8FsrumlVY/DNVvUSDIipiq9PbP4H99TXN1o746o -RaNa07rq1hoCgMSSy+85SagCoxlmyE+D+of9SsMY8Ol9t0rdzpobBuhyJ/o5dfvj -KwIDAQAB ------END PUBLIC KEY----- \ No newline at end of file diff --git a/samples/boot/oauth2resourceserver-multitenancy/README.adoc b/samples/boot/oauth2resourceserver-multitenancy/README.adoc deleted file mode 100644 index 97674479bd..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/README.adoc +++ /dev/null @@ -1,155 +0,0 @@ -= OAuth 2.0 Resource Server Sample - -This sample demonstrates integrating Resource Server with a mock Authorization Server, though it can be modified to integrate -with your favorite Authorization Server. - -With it, you can run the integration tests or run the application as a stand-alone service to explore how you can -secure your own service with OAuth 2.0 Bearer Tokens using Spring Security. - -== 1. Running the tests - -To run the tests, do: - -```bash -./gradlew integrationTest -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplicationTests` from there. - -=== What is it doing? - -By default, the tests are pointing at a mock Authorization Server instance. - -The tests are configured with a set of hard-coded tokens originally obtained from the mock Authorization Server, -and each makes a query to the Resource Server with their corresponding token. - -The Resource Server subsequently verifies with the Authorization Server and authorizes the request, returning either the -phrase - -```bash -Hello, subject for tenant one! -``` - -where "subject" is the value of the `sub` field in the JWT sent in the `Authorization` header, - -or the phrase -```bash -Hello, subject for tenant two! -``` -where "subject" is the value of the `sub` field in the Introspection response from the Authorization Server. - - -== 2. Running the app - -To run as a stand-alone application, do: - -```bash -./gradlew bootRun -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplication` from there. - -=== Authorizing with tenantOne (JWT) - -Once it is up, you can use the following token: - -```bash -export TOKEN=eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjo0NjgzODA1MTI4fQ.ULEPdHG-MK5GlrTQMhgqcyug2brTIZaJIrahUeq9zaiwUSdW83fJ7W1IDd2Z3n4a25JY2uhEcoV95lMfccHR6y_2DLrNvfta22SumY9PEDF2pido54LXG6edIGgarnUbJdR4rpRe_5oRGVa8gDx8FnuZsNv6StSZHAzw5OsuevSTJ1UbJm4UfX3wiahFOQ2OI6G-r5TB2rQNdiPHuNyzG5yznUqRIZ7-GCoMqHMaC-1epKxiX8gYXRROuUYTtcMNa86wh7OVDmvwVmFioRcR58UWBRoO1XQexTtOQq_t8KYsrPZhb9gkyW8x2bAQF-d0J0EJY8JslaH6n4RBaZISww -``` - -And then make this request: - -```bash -curl -H "tenant: one" -H "Authorization: Bearer $TOKEN" localhost:8080 -``` - -Which will respond with the phrase: - -```bash -Hello, subject for tenant one! -``` - -where `subject` is the value of the `sub` field in the JWT sent in the `Authorization` header. - -Or this: - -```bash -export TOKEN=eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQiLCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgUOBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwINafU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_QlR44vmRqS5ncrF-1R0EGcPX49U6A - -curl -H "tenant: one" -H "Authorization: Bearer $TOKEN" localhost:8080/message -``` - -Will respond with: - -```bash -secret message for tenant one -``` - -=== Authorizing with tenantTwo (Opaque token) - -Once it is up, you can use the following token: - -```bash -export TOKEN=00ed5855-1869-47a0-b0c9-0f3ce520aee7 -``` - -And then make this request: - -```bash -curl -H "tenant: two" -H "Authorization: Bearer $TOKEN" localhost:8080 -``` - -Which will respond with the phrase: - -```bash -Hello, subject for tenant two! -``` - -where `subject` is the value of the `sub` field in the Introspection response from the Authorization Server. - -Or this: - -```bash -export TOKEN=b43d1500-c405-4dc9-b9c9-6cfd966c34c9 - -curl -H "tenant: two" -H "Authorization: Bearer $TOKEN" localhost:8080/message -``` - -Will respond with: - -```bash -secret message for tenant two -``` - -== 2. Testing against other Authorization Servers - -_In order to use this sample, your Authorization Server must support JWTs that either use the "scope" or "scp" attribute._ - -To change the sample to point at your Authorization Server, simply find these properties in the `application.yml`: - -```yaml -tenantOne.jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json -tenantTwo.introspection-uri: ${mockwebserver.url}/introspect -tenantTwo.introspection-client-id: client -tenantTwo.introspection-client-secret: secret -``` - -And change the properties to your Authorization Server's JWK set endpoint and -introspection endpoint, including its client id and secret - -```yaml -tenantOne.jwk-set-uri: https://dev-123456.oktapreview.com/oauth2/default/v1/keys -tenantTwo.introspection-uri: https://dev-123456.oktapreview.com/oauth2/default/v1/introspect -tenantTwo.introspection-client-id: client -tenantTwo.introspection-client-secret: secret -``` - -And then you can run the app the same as before: - -```bash -./gradlew bootRun -``` - -Make sure to obtain valid tokens from your Authorization Server in order to play with the sample Resource Server. -To use the `/` endpoint, any valid token from your Authorization Server will do. -To use the `/message` endpoint, the token should have the `message:read` scope. diff --git a/samples/boot/oauth2resourceserver-multitenancy/spring-security-samples-boot-oauth2resourceserver-multitenancy.gradle b/samples/boot/oauth2resourceserver-multitenancy/spring-security-samples-boot-oauth2resourceserver-multitenancy.gradle deleted file mode 100644 index 9074842b18..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/spring-security-samples-boot-oauth2resourceserver-multitenancy.gradle +++ /dev/null @@ -1,14 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-jose') - compile project(':spring-security-oauth2-resource-server') - - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'com.nimbusds:oauth2-oidc-sdk' - compile 'com.squareup.okhttp3:mockwebserver' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java b/samples/boot/oauth2resourceserver-multitenancy/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java deleted file mode 100644 index be6d3f559c..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.hamcrest.Matchers.containsString; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * Integration tests for {@link OAuth2ResourceServerApplication} - * - * @author Josh Cummings - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -public class OAuth2ResourceServerApplicationITests { - - String tenantOneNoScopesToken = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjo0NjgzODA1MTI4fQ.ULEPdHG-MK5GlrTQMhgqcyug2brTIZaJIrahUeq9zaiwUSdW83fJ7W1IDd2Z3n4a25JY2uhEcoV95lMfccHR6y_2DLrNvfta22SumY9PEDF2pido54LXG6edIGgarnUbJdR4rpRe_5oRGVa8gDx8FnuZsNv6StSZHAzw5OsuevSTJ1UbJm4UfX3wiahFOQ2OI6G-r5TB2rQNdiPHuNyzG5yznUqRIZ7-GCoMqHMaC-1epKxiX8gYXRROuUYTtcMNa86wh7OVDmvwVmFioRcR58UWBRoO1XQexTtOQq_t8KYsrPZhb9gkyW8x2bAQF-d0J0EJY8JslaH6n4RBaZISww"; - String tenantOneMessageReadToken = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQiLCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgUOBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwINafU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_QlR44vmRqS5ncrF-1R0EGcPX49U6A"; - String tenantTwoNoScopesToken = "00ed5855-1869-47a0-b0c9-0f3ce520aee7"; - String tenantTwoMessageReadToken = "b43d1500-c405-4dc9-b9c9-6cfd966c34c9"; - - @Autowired - MockMvc mvc; - - @Test - public void tenantOnePerformWhenValidBearerTokenThenAllows() - throws Exception { - - this.mvc.perform(get("/") - .header("tenant", "one") - .header("Authorization", "Bearer " + this.tenantOneNoScopesToken)) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("Hello, subject for tenant one!"))); - } - - @Test - public void tenantOnePerformWhenValidBearerTokenThenScopedRequestsAlsoWork() - throws Exception { - - this.mvc.perform(get("/message") - .header("tenant", "one") - .header("Authorization", "Bearer " + this.tenantOneMessageReadToken)) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("secret message for tenant one"))); - } - - @Test - public void tenantOnePerformWhenInsufficientlyScopedBearerTokenThenDeniesScopedMethodAccess() - throws Exception { - - this.mvc.perform(get("/message") - .header("tenant", "one") - .header("Authorization", "Bearer " + this.tenantOneNoScopesToken)) - .andExpect(status().isForbidden()) - .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, - containsString("Bearer error=\"insufficient_scope\""))); - } - - @Test - public void tenantTwoPerformWhenValidBearerTokenThenAllows() - throws Exception { - - this.mvc.perform(get("/") - .header("tenant", "two") - .header("Authorization", "Bearer " + this.tenantTwoNoScopesToken)) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("Hello, subject for tenant two!"))); - } - - @Test - public void tenantTwoPerformWhenValidBearerTokenThenScopedRequestsAlsoWork() - throws Exception { - - this.mvc.perform(get("/message") - .header("tenant", "two") - .header("Authorization", "Bearer " + this.tenantTwoMessageReadToken)) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("secret message for tenant two"))); - } - - @Test - public void tenantTwoPerformWhenInsufficientlyScopedBearerTokenThenDeniesScopedMethodAccess() - throws Exception { - - this.mvc.perform(get("/message") - .header("tenant", "two") - .header("Authorization", "Bearer " + this.tenantTwoNoScopesToken)) - .andExpect(status().isForbidden()) - .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, - containsString("Bearer error=\"insufficient_scope\""))); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidTenantPerformWhenValidBearerTokenThenThrowsException() - throws Exception { - - this.mvc.perform(get("/") - .header("tenant", "three") - .header("Authorization", "Bearer " + this.tenantOneNoScopesToken)); - } -} diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java b/samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java deleted file mode 100644 index f6f664891b..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.boot.SpringApplication; -import org.springframework.core.env.ConfigurableEnvironment; - -/** - * @author Rob Winch - */ -public class MockWebServerEnvironmentPostProcessor - implements EnvironmentPostProcessor, DisposableBean { - - private final MockWebServerPropertySource propertySource = new MockWebServerPropertySource(); - - @Override - public void postProcessEnvironment(ConfigurableEnvironment environment, - SpringApplication application) { - environment.getPropertySources().addFirst(this.propertySource); - } - - @Override - public void destroy() throws Exception { - this.propertySource.destroy(); - } -} diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java b/samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java deleted file mode 100644 index 9e3f58e628..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import java.io.IOException; -import java.util.Base64; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import okhttp3.mockwebserver.Dispatcher; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import okio.Buffer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.core.env.PropertySource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - -/** - * @author Rob Winch - */ -public class MockWebServerPropertySource extends PropertySource implements - DisposableBean { - - // introspection endpoint - - private static final MockResponse NO_SCOPES_RESPONSE = response( - "{\n" + - " \"active\": true,\n" + - " \"sub\": \"subject\"\n" + - " }", - 200 - ); - - private static final MockResponse MESSASGE_READ_SCOPE_RESPONSE = response( - "{\n" + - " \"active\": true,\n" + - " \"scope\" : \"message:read\"," + - " \"sub\": \"subject\"\n" + - " }", - 200 - ); - - private static final MockResponse INACTIVE_RESPONSE = response( - "{\n" + - " \"active\": false,\n" + - " }", - 200 - ); - - private static final MockResponse BAD_REQUEST_RESPONSE = response( - "{ \"message\" : \"This mock authorization server requires a username and password of " + - "client/secret and a POST body of token=${token}\" }", - 400 - ); - - private static final MockResponse NOT_FOUND_RESPONSE = response( - "{ \"message\" : \"This mock authorization server responds to just two requests: POST /introspect" + - " and GET /.well-known/jwks.json.\" }", - 404 - ); - - // jwks endpoint - - private static final MockResponse JWKS_RESPONSE = response( - "{\"keys\":[{\"p\":\"2p-ViY7DE9ZrdWQb544m0Jp7Cv03YCSljqfim9pD4ALhObX0OrAznOiowTjwBky9JGffMwDBVSfJSD9TSU7aH2sbbfi0bZLMdekKAuimudXwUqPDxrrg0BCyvCYgLmKjbVT3zcdylWSog93CNTxGDPzauu-oc0XPNKCXnaDpNvE\",\"kty\":\"RSA\",\"q\":\"sP_QYavrpBvSJ86uoKVGj2AGl78CSsAtpf1ybSY5TwUlorXSdqapRbY69Y271b0aMLzlleUn9ZTBO1dlKV2_dw_lPADHVia8z3pxL-8sUhIXLsgj4acchMk4c9YX-sFh07xENnyZ-_TXm3llPLuL67HUfBC2eKe800TmCYVWc9U\",\"d\":\"bn1nFxCQT4KLTHqo8mo9HvHD0cRNRNdWcKNnnEQkCF6tKbt-ILRyQGP8O40axLd7CoNVG9c9p_-g4-2kwCtLJNv_STLtwfpCY7VN5o6-ZIpfTjiW6duoPrLWq64Hm_4LOBQTiZfUPcLhsuJRHbWqakj-kV_YbUyC2Ocf_dd8IAQcSrAU2SCcDebhDCWwRUFvaa9V5eq0851S9goaA-AJz-JXyePH6ZFr8JxmWkWxYZ5kdcMD-sm9ZbxE0CaEk32l4fE4hR-L8x2dDtjWA-ahKCZ091z-gV3HWtR2JOjvxoNRjxUo3UxaGiFJHWNIl0EYUJZu1Cb-5wIlEI7wPx5mwQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"qi\":\"qS0OK48M2CIAA6_4Wdw4EbCaAfcTLf5Oy9t5BOF_PFUKqoSpZ6JsT5H0a_4zkjt-oI969v78OTlvBKbmEyKO-KeytzHBAA5CsLmVcz0THrMSg6oXZqu66MPnvWoZN9FEN5TklPOvBFm8Bg1QZ3k-YMVaM--DLvhaYR95_mqaz50\",\"dp\":\"Too2NozLGD1XrXyhabZvy1E0EuaVFj0UHQPDLSpkZ_2g3BK6Art6T0xmE8RYtmqrKIEIdlI3IliAvyvAx_1D7zWTTRaj-xlZyqJFrnXWL7zj8UxT8PkB-r2E-ILZ3NAi1gxIWezlBTZ8M6NfObDFmbTc_3tJkN_raISo8z_ziIE\",\"dq\":\"U0yhSkY5yOsa9YcMoigGVBWSJLpNHtbg5NypjHrPv8OhWbkOSq7WvSstBkFk5AtyFvvfZLMLIkWWxxGzV0t6f1MoxBtttLrYYyCxwihiiGFhLbAdSuZ1wnxcqA9bC7UVECvrQmVTpsMs8UupfHKbQBpZ8OWAqrnuYNNtG4_4Bt0\",\"n\":\"lygtuZj0lJjqOqIWocF8Bb583QDdq-aaFg8PesOp2-EDda6GqCpL-_NZVOflNGX7XIgjsWHcPsQHsV9gWuOzSJ0iEuWvtQ6eGBP5M6m7pccLNZfwUse8Cb4Ngx3XiTlyuqM7pv0LPyppZusfEHVEdeelou7Dy9k0OQ_nJTI3b2E1WBoHC58CJ453lo4gcBm1efURN3LIVc1V9NQY_ESBKVdwqYyoJPEanURLVGRd6cQKn6YrCbbIRHjqAyqOE-z3KmgDJnPriljfR5XhSGyM9eqD9Xpy6zu_MAeMJJfSArp857zLPk-Wf5VP9STAcjyfdBIybMKnwBYr2qHMT675hQ\"}]}", - 200 - ); - - /** - * Name of the random {@link PropertySource}. - */ - public static final String MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME = "mockwebserver"; - - private static final String NAME = "mockwebserver.url"; - - private static final Log logger = LogFactory.getLog(MockWebServerPropertySource.class); - - private boolean started; - - public MockWebServerPropertySource() { - super(MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME, new MockWebServer()); - } - - @Override - public Object getProperty(String name) { - if (!name.equals(NAME)) { - return null; - } - if (logger.isTraceEnabled()) { - logger.trace("Looking up the url for '" + name + "'"); - } - String url = getUrl(); - return url; - } - - @Override - public void destroy() throws Exception { - getSource().shutdown(); - } - - /** - * Get's the URL (i.e. "http://localhost:123456") - * @return - */ - private String getUrl() { - MockWebServer mockWebServer = getSource(); - if (!this.started) { - intializeMockWebServer(mockWebServer); - } - String url = mockWebServer.url("").url().toExternalForm(); - return url.substring(0, url.length() - 1); - } - - private void intializeMockWebServer(MockWebServer mockWebServer) { - Dispatcher dispatcher = new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest request) { - return doDispatch(request); - } - }; - - mockWebServer.setDispatcher(dispatcher); - try { - mockWebServer.start(); - this.started = true; - } catch (IOException e) { - throw new RuntimeException("Could not start " + mockWebServer, e); - } - } - - private MockResponse doDispatch(RecordedRequest request) { - if ("/.well-known/jwks.json".equals(request.getPath())) { - return JWKS_RESPONSE; - } - - if ("/introspect".equals(request.getPath())) { - return Optional.ofNullable(request.getHeader(HttpHeaders.AUTHORIZATION)) - .filter((authorization) -> isAuthorized(authorization, "client", "secret")) - .map((authorization) -> parseBody(request.getBody())) - .map((parameters) -> parameters.get("token")) - .map((token) -> { - if ("00ed5855-1869-47a0-b0c9-0f3ce520aee7".equals(token)) { - return NO_SCOPES_RESPONSE; - } else if ("b43d1500-c405-4dc9-b9c9-6cfd966c34c9".equals(token)) { - return MESSASGE_READ_SCOPE_RESPONSE; - } else { - return INACTIVE_RESPONSE; - } - }) - .orElse(BAD_REQUEST_RESPONSE); - } - - return NOT_FOUND_RESPONSE; - } - - private boolean isAuthorized(String authorization, String username, String password) { - String[] values = new String(Base64.getDecoder().decode(authorization.substring(6))).split(":"); - return username.equals(values[0]) && password.equals(values[1]); - } - - private Map parseBody(Buffer body) { - return Stream.of(body.readUtf8().split("&")) - .map((parameter) -> parameter.split("=")) - .collect(Collectors.toMap((parts) -> parts[0], (parts) -> parts[1])); - } - - private static MockResponse response(String body, int status) { - return new MockResponse() - .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .setResponseCode(status) - .setBody(body); - } - -} diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/package-info.java b/samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/package-info.java deleted file mode 100644 index 4db05821da..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/org/springframework/boot/env/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This provides integration of a {@link okhttp3.mockwebserver.MockWebServer} and the - * {@link org.springframework.core.env.Environment} - * @author Rob Winch - */ -package org.springframework.boot.env; diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerApplication.java b/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerApplication.java deleted file mode 100644 index d5c70cc70d..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Josh Cummings - */ -@SpringBootApplication -public class OAuth2ResourceServerApplication { - - public static void main(String[] args) { - SpringApplication.run(OAuth2ResourceServerApplication.class, args); - } -} diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerController.java b/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerController.java deleted file mode 100644 index 1dce6e718a..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerController.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Josh Cummings - */ -@RestController -public class OAuth2ResourceServerController { - - @GetMapping("/") - public String index(@AuthenticationPrincipal OAuth2AuthenticatedPrincipal token, @RequestHeader("tenant") String tenant) { - String subject = token.getAttribute("sub"); - return String.format("Hello, %s for tenant %s!", subject, tenant); - } - - @GetMapping("/message") - public String message(@RequestHeader("tenant") String tenant) { - return String.format("secret message for tenant %s", tenant); - } -} diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java deleted file mode 100644 index 75bf3865b9..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import javax.servlet.http.HttpServletRequest; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.AuthenticationManagerResolver; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -/** - * @author Josh Cummings - */ -@EnableWebSecurity -public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter { - - @Autowired - AuthenticationManagerResolver authenticationManagerResolver; - - @Override - protected void configure(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeRequests((authz) -> authz - .antMatchers("/message/**").hasAuthority("SCOPE_message:read") - .anyRequest().authenticated() - ) - .oauth2ResourceServer((oauth2) -> oauth2 - .authenticationManagerResolver(this.authenticationManagerResolver) - ); - // @formatter:on - } -} diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/TenantAuthenticationManagerResolver.java b/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/TenantAuthenticationManagerResolver.java deleted file mode 100644 index 939bfc0b8b..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/TenantAuthenticationManagerResolver.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import javax.servlet.http.HttpServletRequest; - -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.AuthenticationManagerResolver; -import org.springframework.security.authentication.ProviderManager; -import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider; -import org.springframework.security.oauth2.server.resource.authentication.JwtBearerTokenAuthenticationConverter; -import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider; -import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; -import org.springframework.stereotype.Component; - -@Component -public class TenantAuthenticationManagerResolver - implements AuthenticationManagerResolver { - - private AuthenticationManager jwt; - private AuthenticationManager opaqueToken; - - public TenantAuthenticationManagerResolver( - JwtDecoder jwtDecoder, OpaqueTokenIntrospector opaqueTokenIntrospector) { - - JwtAuthenticationProvider jwtAuthenticationProvider = new JwtAuthenticationProvider(jwtDecoder); - jwtAuthenticationProvider.setJwtAuthenticationConverter(new JwtBearerTokenAuthenticationConverter()); - this.jwt = new ProviderManager(jwtAuthenticationProvider); - this.opaqueToken = new ProviderManager(new OpaqueTokenAuthenticationProvider(opaqueTokenIntrospector)); - } - - @Override - public AuthenticationManager resolve(HttpServletRequest request) { - String tenant = request.getHeader("tenant"); - if ("one".equals(tenant)) { - return this.jwt; - } - if ("two".equals(tenant)) { - return this.opaqueToken; - } - throw new IllegalArgumentException("unknown tenant"); - } -} diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/resources/META-INF/spring.factories b/samples/boot/oauth2resourceserver-multitenancy/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 37b447c970..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=org.springframework.boot.env.MockWebServerEnvironmentPostProcessor diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/resources/application.yml b/samples/boot/oauth2resourceserver-multitenancy/src/main/resources/application.yml deleted file mode 100644 index 6447ad0d94..0000000000 --- a/samples/boot/oauth2resourceserver-multitenancy/src/main/resources/application.yml +++ /dev/null @@ -1,10 +0,0 @@ -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json - opaquetoken: - introspection-uri: ${mockwebserver.url}/introspect - client-id: client - client-secret: secret diff --git a/samples/boot/oauth2resourceserver-opaque/README.adoc b/samples/boot/oauth2resourceserver-opaque/README.adoc deleted file mode 100644 index fc6add9a1f..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/README.adoc +++ /dev/null @@ -1,114 +0,0 @@ -= OAuth 2.0 Resource Server Sample - -This sample demonstrates integrating Resource Server with a mock Authorization Server, though it can be modified to integrate -with your favorite Authorization Server. - -With it, you can run the integration tests or run the application as a stand-alone service to explore how you can -secure your own service with OAuth 2.0 Opaque Bearer Tokens using Spring Security. - -== 1. Running the tests - -To run the tests, do: - -```bash -./gradlew integrationTest -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplicationTests` from there. - -=== What is it doing? - -By default, the tests are pointing at a mock Authorization Server instance. - -The tests are configured with a set of hard-coded tokens originally obtained from the mock Authorization Server, -and each makes a query to the Resource Server with their corresponding token. - -The Resource Server subsquently verifies with the Authorization Server and authorizes the request, returning the phrase - -```bash -Hello, subject! -``` - -where "subject" is the value of the `sub` field in the JWT returned by the Authorization Server. - -== 2. Running the app - -To run as a stand-alone application, do: - -```bash -./gradlew bootRun -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplication` from there. - -Once it is up, you can use the following token: - -```bash -export TOKEN=00ed5855-1869-47a0-b0c9-0f3ce520aee7 -``` - -And then make this request: - -```bash -curl -H "Authorization: Bearer $TOKEN" localhost:8080 -``` - -Which will respond with the phrase: - -```bash -Hello, subject! -``` - -where `subject` is the value of the `sub` field in the JWT returned by the Authorization Server. - -Or this: - -```bash -export TOKEN=b43d1500-c405-4dc9-b9c9-6cfd966c34c9 - -curl -H "Authorization: Bearer $TOKEN" localhost:8080/message -``` - -Will respond with: - -```bash -secret message -``` - -== 2. Testing against other Authorization Servers - -_In order to use this sample, your Authorization Server must support Opaque Tokens and the Introspection Endpoint. - -To change the sample to point at your Authorization Server, simply find this property in the `application.yml`: - -```yaml -spring: - security: - oauth2: - resourceserver: - opaque: - introspection-uri: ${mockwebserver.url}/introspect - introspection-client-id: client - introspection-client-secret: secret -``` - -And change the property to your Authorization Server's Introspection endpoint, including its client id and secret: - -```yaml -spring: - security: - oauth2: - resourceserver: - opaque: - introspection-uri: ${mockwebserver.url}/introspect -``` - -And then you can run the app the same as before: - -```bash -./gradlew bootRun -``` - -Make sure to obtain valid tokens from your Authorization Server in order to play with the sample Resource Server. -To use the `/` endpoint, any valid token from your Authorization Server will do. -To use the `/message` endpoint, the token should have the `message:read` scope. diff --git a/samples/boot/oauth2resourceserver-opaque/spring-security-samples-boot-oauth2resourceserver-opaque.gradle b/samples/boot/oauth2resourceserver-opaque/spring-security-samples-boot-oauth2resourceserver-opaque.gradle deleted file mode 100644 index 9074842b18..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/spring-security-samples-boot-oauth2resourceserver-opaque.gradle +++ /dev/null @@ -1,14 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-jose') - compile project(':spring-security-oauth2-resource-server') - - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'com.nimbusds:oauth2-oidc-sdk' - compile 'com.squareup.okhttp3:mockwebserver' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/oauth2resourceserver-opaque/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java b/samples/boot/oauth2resourceserver-opaque/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java deleted file mode 100644 index 10bd3fc7ec..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.RequestPostProcessor; - -import static org.hamcrest.Matchers.containsString; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * Integration tests for {@link OAuth2ResourceServerApplication} - * - * @author Josh Cummings - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -@ActiveProfiles("test") -public class OAuth2ResourceServerApplicationITests { - - String noScopesToken = "00ed5855-1869-47a0-b0c9-0f3ce520aee7"; - String messageReadToken = "b43d1500-c405-4dc9-b9c9-6cfd966c34c9"; - - @Autowired - MockMvc mvc; - - @Test - public void performWhenValidBearerTokenThenAllows() - throws Exception { - - this.mvc.perform(get("/").with(bearerToken(this.noScopesToken))) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("Hello, subject!"))); - } - - @Test - public void performWhenValidBearerTokenThenScopedRequestsAlsoWork() - throws Exception { - - this.mvc.perform(get("/message").with(bearerToken(this.messageReadToken))) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("secret message"))); - } - - @Test - public void performWhenInsufficientlyScopedBearerTokenThenDeniesScopedMethodAccess() - throws Exception { - - this.mvc.perform(get("/message").with(bearerToken(this.noScopesToken))) - .andExpect(status().isForbidden()) - .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, - containsString("Bearer error=\"insufficient_scope\""))); - } - - private static class BearerTokenRequestPostProcessor implements RequestPostProcessor { - private String token; - - BearerTokenRequestPostProcessor(String token) { - this.token = token; - } - - @Override - public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { - request.addHeader("Authorization", "Bearer " + this.token); - return request; - } - } - - private static BearerTokenRequestPostProcessor bearerToken(String token) { - return new BearerTokenRequestPostProcessor(token); - } -} diff --git a/samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java b/samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java deleted file mode 100644 index f6f664891b..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.boot.SpringApplication; -import org.springframework.core.env.ConfigurableEnvironment; - -/** - * @author Rob Winch - */ -public class MockWebServerEnvironmentPostProcessor - implements EnvironmentPostProcessor, DisposableBean { - - private final MockWebServerPropertySource propertySource = new MockWebServerPropertySource(); - - @Override - public void postProcessEnvironment(ConfigurableEnvironment environment, - SpringApplication application) { - environment.getPropertySources().addFirst(this.propertySource); - } - - @Override - public void destroy() throws Exception { - this.propertySource.destroy(); - } -} diff --git a/samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java b/samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java deleted file mode 100644 index 0bc6b57558..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import java.io.IOException; -import java.util.Base64; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import okhttp3.mockwebserver.Dispatcher; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import okio.Buffer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.core.env.PropertySource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - -/** - * @author Rob Winch - */ -public class MockWebServerPropertySource extends PropertySource implements - DisposableBean { - - private static final MockResponse NO_SCOPES_RESPONSE = response( - "{\n" + - " \"active\": true,\n" + - " \"sub\": \"subject\"\n" + - " }", - 200 - ); - - private static final MockResponse MESSASGE_READ_SCOPE_RESPONSE = response( - "{\n" + - " \"active\": true,\n" + - " \"scope\" : \"message:read\"," + - " \"sub\": \"subject\"\n" + - " }", - 200 - ); - - private static final MockResponse INACTIVE_RESPONSE = response( - "{\n" + - " \"active\": false,\n" + - " }", - 200 - ); - - private static final MockResponse BAD_REQUEST_RESPONSE = response( - "{ \"message\" : \"This mock authorization server requires a username and password of " + - "client/secret and a POST body of token=${token}\" }", - 400 - ); - - private static final MockResponse NOT_FOUND_RESPONSE = response( - "{ \"message\" : \"This mock authorization server responds to just one request: POST /introspect.\" }", - 404 - ); - - /** - * Name of the random {@link PropertySource}. - */ - public static final String MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME = "mockwebserver"; - - private static final String NAME = "mockwebserver.url"; - - private static final Log logger = LogFactory.getLog(MockWebServerPropertySource.class); - - private boolean started; - - public MockWebServerPropertySource() { - super(MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME, new MockWebServer()); - } - - @Override - public Object getProperty(String name) { - if (!name.equals(NAME)) { - return null; - } - if (logger.isTraceEnabled()) { - logger.trace("Looking up the url for '" + name + "'"); - } - String url = getUrl(); - return url; - } - - @Override - public void destroy() throws Exception { - getSource().shutdown(); - } - - /** - * Get's the URL (e.g. "http://localhost:123456") - * @return - */ - private String getUrl() { - MockWebServer mockWebServer = getSource(); - if (!this.started) { - initializeMockWebServer(mockWebServer); - } - String url = mockWebServer.url("").url().toExternalForm(); - return url.substring(0, url.length() - 1); - } - - private void initializeMockWebServer(MockWebServer mockWebServer) { - Dispatcher dispatcher = new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest request) { - return doDispatch(request); - } - }; - - mockWebServer.setDispatcher(dispatcher); - try { - mockWebServer.start(); - this.started = true; - } catch (IOException e) { - throw new RuntimeException("Could not start " + mockWebServer, e); - } - } - - private MockResponse doDispatch(RecordedRequest request) { - if ("/introspect".equals(request.getPath())) { - return Optional.ofNullable(request.getHeader(HttpHeaders.AUTHORIZATION)) - .filter((authorization) -> isAuthorized(authorization, "client", "secret")) - .map((authorization) -> parseBody(request.getBody())) - .map((parameters) -> parameters.get("token")) - .map((token) -> { - if ("00ed5855-1869-47a0-b0c9-0f3ce520aee7".equals(token)) { - return NO_SCOPES_RESPONSE; - } else if ("b43d1500-c405-4dc9-b9c9-6cfd966c34c9".equals(token)) { - return MESSASGE_READ_SCOPE_RESPONSE; - } else { - return INACTIVE_RESPONSE; - } - }) - .orElse(BAD_REQUEST_RESPONSE); - } - - return NOT_FOUND_RESPONSE; - } - - private boolean isAuthorized(String authorization, String username, String password) { - String[] values = new String(Base64.getDecoder().decode(authorization.substring(6))).split(":"); - return username.equals(values[0]) && password.equals(values[1]); - } - - private Map parseBody(Buffer body) { - return Stream.of(body.readUtf8().split("&")) - .map((parameter) -> parameter.split("=")) - .collect(Collectors.toMap((parts) -> parts[0], (parts) -> parts[1])); - } - - private static MockResponse response(String body, int status) { - return new MockResponse() - .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .setResponseCode(status) - .setBody(body); - } - -} diff --git a/samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/package-info.java b/samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/package-info.java deleted file mode 100644 index 22b7245ebb..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/main/java/org/springframework/boot/env/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This provides integration of a {@link okhttp3.mockwebserver.MockWebServer} and the - * {@link org.springframework.core.env.Environment} - * - * @author Rob Winch - */ -package org.springframework.boot.env; diff --git a/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerApplication.java b/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerApplication.java deleted file mode 100644 index d5c70cc70d..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Josh Cummings - */ -@SpringBootApplication -public class OAuth2ResourceServerApplication { - - public static void main(String[] args) { - SpringApplication.run(OAuth2ResourceServerApplication.class, args); - } -} diff --git a/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerController.java b/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerController.java deleted file mode 100644 index 857d29be66..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerController.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Josh Cummings - */ -@RestController -public class OAuth2ResourceServerController { - - @GetMapping("/") - public String index(@AuthenticationPrincipal(expression="subject") String subject) { - return String.format("Hello, %s!", subject); - } - - @GetMapping("/message") - public String message() { - return "secret message"; - } - - @PostMapping("/message") - public String createMessage(@RequestBody String message) { - return String.format("Message was created. Content: %s", message); - } -} diff --git a/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java deleted file mode 100644 index 6fc3444c73..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -/** - * @author Josh Cummings - */ -@EnableWebSecurity -public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter { - - @Value("${spring.security.oauth2.resourceserver.opaque.introspection-uri}") String introspectionUri; - @Value("${spring.security.oauth2.resourceserver.opaque.introspection-client-id}") String clientId; - @Value("${spring.security.oauth2.resourceserver.opaque.introspection-client-secret}") String clientSecret; - - @Override - protected void configure(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeRequests((authorizeRequests) -> - authorizeRequests - .antMatchers(HttpMethod.GET, "/message/**").hasAuthority("SCOPE_message:read") - .antMatchers(HttpMethod.POST, "/message/**").hasAuthority("SCOPE_message:write") - .anyRequest().authenticated() - ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .opaqueToken((opaqueToken) -> - opaqueToken - .introspectionUri(this.introspectionUri) - .introspectionClientCredentials(this.clientId, this.clientSecret) - ) - ); - // @formatter:on - } -} diff --git a/samples/boot/oauth2resourceserver-opaque/src/main/resources/META-INF/spring.factories b/samples/boot/oauth2resourceserver-opaque/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 37b447c970..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=org.springframework.boot.env.MockWebServerEnvironmentPostProcessor diff --git a/samples/boot/oauth2resourceserver-opaque/src/main/resources/application.yml b/samples/boot/oauth2resourceserver-opaque/src/main/resources/application.yml deleted file mode 100644 index a7dcfead94..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/main/resources/application.yml +++ /dev/null @@ -1,8 +0,0 @@ -spring: - security: - oauth2: - resourceserver: - opaque: - introspection-uri: ${mockwebserver.url}/introspect - introspection-client-id: client - introspection-client-secret: secret diff --git a/samples/boot/oauth2resourceserver-opaque/src/test/java/sample/OAuth2ResourceServerControllerTests.java b/samples/boot/oauth2resourceserver-opaque/src/test/java/sample/OAuth2ResourceServerControllerTests.java deleted file mode 100644 index ee3318f246..0000000000 --- a/samples/boot/oauth2resourceserver-opaque/src/test/java/sample/OAuth2ResourceServerControllerTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.hamcrest.CoreMatchers.is; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.opaqueToken; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * @author Josh Cummings - * @since 5.3 - */ -@RunWith(SpringRunner.class) -@WebMvcTest(OAuth2ResourceServerController.class) -public class OAuth2ResourceServerControllerTests { - - @Autowired - MockMvc mvc; - - @Test - public void indexGreetsAuthenticatedUser() throws Exception { - this.mvc.perform(get("/").with(opaqueToken().attributes((a) -> a.put("sub", "ch4mpy")))) - .andExpect(content().string(is("Hello, ch4mpy!"))); - } - - @Test - public void messageCanBeReadWithScopeMessageReadAuthority() throws Exception { - this.mvc.perform(get("/message").with(opaqueToken().attributes((a) -> a.put("scope", "message:read")))) - .andExpect(content().string(is("secret message"))); - - this.mvc.perform(get("/message") - .with(jwt().authorities(new SimpleGrantedAuthority(("SCOPE_message:read"))))) - .andExpect(content().string(is("secret message"))); - } - - @Test - public void messageCanNotBeReadWithoutScopeMessageReadAuthority() throws Exception { - this.mvc.perform(get("/message").with(opaqueToken())) - .andExpect(status().isForbidden()); - } - - @Test - public void messageCanNotBeCreatedWithoutAnyScope() throws Exception { - this.mvc.perform(post("/message") - .content("Hello message") - .with(opaqueToken())) - .andExpect(status().isForbidden()); - } - - @Test - public void messageCanNotBeCreatedWithScopeMessageReadAuthority() throws Exception { - this.mvc.perform(post("/message") - .content("Hello message") - .with(opaqueToken().authorities(new SimpleGrantedAuthority("SCOPE_message:read")))) - .andExpect(status().isForbidden()); - } - - @Test - public void messageCanBeCreatedWithScopeMessageWriteAuthority() throws Exception { - this.mvc.perform(post("/message") - .content("Hello message") - .with(opaqueToken().authorities(new SimpleGrantedAuthority("SCOPE_message:write")))) - .andExpect(status().isOk()) - .andExpect(content().string(is("Message was created. Content: Hello message"))); - } -} diff --git a/samples/boot/oauth2resourceserver-static/README.adoc b/samples/boot/oauth2resourceserver-static/README.adoc deleted file mode 100644 index ecc530d724..0000000000 --- a/samples/boot/oauth2resourceserver-static/README.adoc +++ /dev/null @@ -1,82 +0,0 @@ -= OAuth 2.0 Resource Server Sample - -This sample demonstrates integrating Resource Server with a pre-configured key. - -With it, you can run the integration tests or run the application as a stand-alone service to explore how you can -secure your own service with OAuth 2.0 Bearer Tokens using Spring Security. - -== 1. Running the tests - -To run the tests, do: - -```bash -./gradlew integrationTest -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplicationITests` from there. - -=== What is it doing? - -By default, the application is configured with an RSA public key that is available in the sample. - -The tests are configured with a set of hard-coded tokens that are signed with the corresponding RSA private key. -Each test makes a query to the Resource Server with their corresponding token. - -The Resource Server subsequently verifies the token against the public key and authorizes the request, returning the phrase - -```bash -Hello, subject! -``` - -where "subject" is the value of the `sub` field in the token. - -== 2. Running the app - -To run as a stand-alone application, do: - -```bash -./gradlew bootRun -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplication` from there. - -Once it is up, you can use the following token: - -```bash -export TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaWF0IjoxNTE2MjM5MDIyfQ.eB2c9xtg5wcCZxZ-o-sH4Mx1JGkqAZwH4_WS0UcDbj_nen0NPBj6CqOEPhr_LZDagb4mM6HoAPJywWWG8b_Ylnn5r2gWDzib2mb0kxIuAjnvVBrpzusw4ItTVvP_srv2DrwcisKYiKqU5X_3ka7MSVvKtswdLY3RXeCJ_S2W9go -``` - -And then make this request: - -```bash -curl -H "Authorization: Bearer $TOKEN" localhost:8080 -``` - -Which will respond with the phrase: - -```bash -Hello, subject! -``` - -where `subject` is the value of the `sub` field in the token. - -Or this: - -```bash -export TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaWF0IjoxNTE2MjM5MDIyLCJzY29wZSI6Im1lc3NhZ2U6cmVhZCJ9.bsRCpUEaiWnzX4OqNxTBqwUD4vxxtPp-CHKTw7XcrglrvZ2lvYXaiZZbCp-hcPhuzMEzEAFuH6s4GZZOWVIX-wT47GdTz9cfA-Z4QPjS2RxePKphFXgBI3jHEpQo94Qya2fJdV4LvgBmA1uM_RTnYY1UbmeYuHKnXrZoGyV8QQQ - -curl -H "Authorization: Bearer $TOKEN" localhost:8080/message -``` - -Will respond with: - -```bash -secret message -``` - -== 3. Testing with Other Tokens - -You can create your own tokens. Simply edit the public key in `OAuth2ResourceServerSecurityConfiguration` to match the private key you use. - -To use the `/` endpoint, any valid token will do. -To use the `/message` endpoint, the token should have the `message:read` scope. diff --git a/samples/boot/oauth2resourceserver-static/spring-security-samples-boot-oauth2resourceserver-static.gradle b/samples/boot/oauth2resourceserver-static/spring-security-samples-boot-oauth2resourceserver-static.gradle deleted file mode 100644 index faba0d5f46..0000000000 --- a/samples/boot/oauth2resourceserver-static/spring-security-samples-boot-oauth2resourceserver-static.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-jose') - compile project(':spring-security-oauth2-resource-server') - - compile 'org.springframework.boot:spring-boot-starter-web' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/oauth2resourceserver-static/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java b/samples/boot/oauth2resourceserver-static/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java deleted file mode 100644 index 851d3bd242..0000000000 --- a/samples/boot/oauth2resourceserver-static/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.RequestPostProcessor; - -import static org.hamcrest.Matchers.containsString; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * Integration tests for {@link OAuth2ResourceServerApplication} - * - * @author Josh Cummings - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -@ActiveProfiles("test") -public class OAuth2ResourceServerApplicationITests { - - String noScopesToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaWF0IjoxNTE2MjM5MDIyfQ.eB2c9xtg5wcCZxZ-o-sH4Mx1JGkqAZwH4_WS0UcDbj_nen0NPBj6CqOEPhr_LZDagb4mM6HoAPJywWWG8b_Ylnn5r2gWDzib2mb0kxIuAjnvVBrpzusw4ItTVvP_srv2DrwcisKYiKqU5X_3ka7MSVvKtswdLY3RXeCJ_S2W9go"; - String messageReadToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaWF0IjoxNTE2MjM5MDIyLCJzY29wZSI6Im1lc3NhZ2U6cmVhZCJ9.bsRCpUEaiWnzX4OqNxTBqwUD4vxxtPp-CHKTw7XcrglrvZ2lvYXaiZZbCp-hcPhuzMEzEAFuH6s4GZZOWVIX-wT47GdTz9cfA-Z4QPjS2RxePKphFXgBI3jHEpQo94Qya2fJdV4LvgBmA1uM_RTnYY1UbmeYuHKnXrZoGyV8QQQ"; - - @Autowired - MockMvc mvc; - - @Test - public void performWhenValidBearerTokenThenAllows() - throws Exception { - - this.mvc.perform(get("/").with(bearerToken(this.noScopesToken))) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("Hello, subject!"))); - } - - @Test - public void performWhenValidBearerTokenThenScopedRequestsAlsoWork() - throws Exception { - - this.mvc.perform(get("/message").with(bearerToken(this.messageReadToken))) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("secret message"))); - } - - @Test - public void performWhenInsufficientlyScopedBearerTokenThenDeniesScopedMethodAccess() - throws Exception { - - this.mvc.perform(get("/message").with(bearerToken(this.noScopesToken))) - .andExpect(status().isForbidden()) - .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, - containsString("Bearer error=\"insufficient_scope\""))); - } - - private static class BearerTokenRequestPostProcessor implements RequestPostProcessor { - private String token; - - BearerTokenRequestPostProcessor(String token) { - this.token = token; - } - - @Override - public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { - request.addHeader("Authorization", "Bearer " + this.token); - return request; - } - } - - private static BearerTokenRequestPostProcessor bearerToken(String token) { - return new BearerTokenRequestPostProcessor(token); - } -} diff --git a/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerApplication.java b/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerApplication.java deleted file mode 100644 index a0841c00f3..0000000000 --- a/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Josh Cummings - */ -@SpringBootApplication -public class OAuth2ResourceServerApplication { - - public static void main(String[] args) { - SpringApplication.run(OAuth2ResourceServerApplication.class, args); - } -} diff --git a/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerController.java b/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerController.java deleted file mode 100644 index f0bcdbe64f..0000000000 --- a/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerController.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Josh Cummings - */ -@RestController -public class OAuth2ResourceServerController { - - @GetMapping("/") - public String index(@AuthenticationPrincipal Jwt jwt) { - return String.format("Hello, %s!", jwt.getSubject()); - } - - @GetMapping("/message") - public String message() { - return "secret message"; - } -} diff --git a/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java deleted file mode 100644 index a57bed2d51..0000000000 --- a/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.security.interfaces.RSAPublicKey; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; - -/** - * @author Josh Cummings - */ -@EnableWebSecurity -public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter { - - @Value("${spring.security.oauth2.resourceserver.jwt.key-value}") - RSAPublicKey key; - - @Override - protected void configure(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeRequests((authorizeRequests) -> - authorizeRequests - .antMatchers("/message/**").hasAuthority("SCOPE_message:read") - .anyRequest().authenticated() - ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .jwt((jwt) -> - jwt.decoder(jwtDecoder()) - ) - ); - // @formatter:on - } - - @Bean - JwtDecoder jwtDecoder() { - return NimbusJwtDecoder.withPublicKey(this.key).build(); - } -} diff --git a/samples/boot/oauth2resourceserver-static/src/main/resources/application.yml b/samples/boot/oauth2resourceserver-static/src/main/resources/application.yml deleted file mode 100644 index 123d342ead..0000000000 --- a/samples/boot/oauth2resourceserver-static/src/main/resources/application.yml +++ /dev/null @@ -1,6 +0,0 @@ -spring: - security: - oauth2: - resourceserver: - jwt: - key-value: classpath:simple.pub diff --git a/samples/boot/oauth2resourceserver-static/src/main/resources/simple.pub b/samples/boot/oauth2resourceserver-static/src/main/resources/simple.pub deleted file mode 100644 index a25c08779e..0000000000 --- a/samples/boot/oauth2resourceserver-static/src/main/resources/simple.pub +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd -UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs -HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D -o2kQ+X5xK9cipRgEKwIDAQAB ------END PUBLIC KEY----- - diff --git a/samples/boot/oauth2resourceserver-webflux/README.adoc b/samples/boot/oauth2resourceserver-webflux/README.adoc deleted file mode 100644 index 75c3fd7b41..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/README.adoc +++ /dev/null @@ -1,112 +0,0 @@ -= OAuth 2.0 Resource Server Sample - -This sample demonstrates integrating Resource Server with a mock Authorization Server, though it can be modified to integrate -with your favorite Authorization Server. - -With it, you can run the integration tests or run the application as a stand-alone service to explore how you can -secure your own service with OAuth 2.0 Bearer Tokens using Spring Security. - -== 1. Running the tests - -To run the tests, do: - -```bash -./gradlew integrationTest -``` - -Or import the project into your IDE and run `ServerOAuth2ResourceServerApplicationTests` from there. - -=== What is it doing? - -By default, the tests are pointing at a mock Authorization Server instance. - -The tests are configured with a set of hard-coded tokens originally obtained from the mock Authorization Server, -and each makes a query to the Resource Server with their corresponding token. - -The Resource Server subsquently verifies with the Authorization Server and authorizes the request, returning the phrase - -```bash -Hello, subject! -``` - -where "subject" is the value of the `sub` field in the JWT returned by the Authorization Server. - -== 2. Running the app - -To run as a stand-alone application, do: - -```bash -./gradlew bootRun -``` - -Or import the project into your IDE and run `ServerOAuth2ResourceServerApplication` from there. - -Once it is up, you can use the following token: - -```bash -export TOKEN=eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjo0NjgzODA1MTI4fQ.ULEPdHG-MK5GlrTQMhgqcyug2brTIZaJIrahUeq9zaiwUSdW83fJ7W1IDd2Z3n4a25JY2uhEcoV95lMfccHR6y_2DLrNvfta22SumY9PEDF2pido54LXG6edIGgarnUbJdR4rpRe_5oRGVa8gDx8FnuZsNv6StSZHAzw5OsuevSTJ1UbJm4UfX3wiahFOQ2OI6G-r5TB2rQNdiPHuNyzG5yznUqRIZ7-GCoMqHMaC-1epKxiX8gYXRROuUYTtcMNa86wh7OVDmvwVmFioRcR58UWBRoO1XQexTtOQq_t8KYsrPZhb9gkyW8x2bAQF-d0J0EJY8JslaH6n4RBaZISww -``` - -And then make this request: - -```bash -curl -H "Authorization: Bearer $TOKEN" localhost:8080 -``` - -Which will respond with the phrase: - -```bash -Hello, subject! -``` - -where `subject` is the value of the `sub` field in the JWT returned by the Authorization Server. - -Or this: - -```bash -export TOKEN=eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQiLCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgUOBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwINafU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_QlR44vmRqS5ncrF-1R0EGcPX49U6A - -curl -H "Authorization: Bearer $TOKEN" localhost:8080/message -``` - -Will respond with: - -```bash -secret message -``` - -== 2. Testing against other Authorization Servers - -_In order to use this sample, your Authorization Server must support JWTs that either use the "scope" or "scp" attribute._ - -To change the sample to point at your Authorization Server, simply find this property in the `application.yml`: - -```yaml -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json -``` - -And change the property to your Authorization Server's JWK set endpoint: - -```yaml -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: https://dev-123456.oktapreview.com/oauth2/default/v1/keys -``` - -And then you can run the app the same as before: - -```bash -./gradlew bootRun -``` - -Make sure to obtain valid tokens from your Authorization Server in order to play with the sample Resource Server. -To use the `/` endpoint, any valid token from your Authorization Server will do. -To use the `/message` endpoint, the token should have the `message:read` scope. diff --git a/samples/boot/oauth2resourceserver-webflux/spring-security-samples-boot-oauth2resourceserver-webflux.gradle b/samples/boot/oauth2resourceserver-webflux/spring-security-samples-boot-oauth2resourceserver-webflux.gradle deleted file mode 100644 index 0d92aef8de..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/spring-security-samples-boot-oauth2resourceserver-webflux.gradle +++ /dev/null @@ -1,16 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-jose') - compile project(':spring-security-oauth2-client') - compile project(':spring-security-oauth2-resource-server') - - compile 'org.springframework.boot:spring-boot-starter-webflux' - compile 'com.squareup.okhttp3:mockwebserver' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' - - testCompile 'com.squareup.okhttp3:mockwebserver' -} diff --git a/samples/boot/oauth2resourceserver-webflux/src/integration-test/java/sample/ServerOAuth2ResourceServerApplicationITests.java b/samples/boot/oauth2resourceserver-webflux/src/integration-test/java/sample/ServerOAuth2ResourceServerApplicationITests.java deleted file mode 100644 index 9cbdcf2b36..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/integration-test/java/sample/ServerOAuth2ResourceServerApplicationITests.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -import java.util.function.Consumer; - -import static org.hamcrest.Matchers.containsString; - -/** - * @author Rob Winch - * @since 5.1 - */ -@SpringBootTest -@AutoConfigureWebTestClient -@RunWith(SpringJUnit4ClassRunner.class) -public class ServerOAuth2ResourceServerApplicationITests { - - Consumer noScopesToken = (http) -> http.setBearerAuth("eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjo0NjgzODA1MTI4fQ.ULEPdHG-MK5GlrTQMhgqcyug2brTIZaJIrahUeq9zaiwUSdW83fJ7W1IDd2Z3n4a25JY2uhEcoV95lMfccHR6y_2DLrNvfta22SumY9PEDF2pido54LXG6edIGgarnUbJdR4rpRe_5oRGVa8gDx8FnuZsNv6StSZHAzw5OsuevSTJ1UbJm4UfX3wiahFOQ2OI6G-r5TB2rQNdiPHuNyzG5yznUqRIZ7-GCoMqHMaC-1epKxiX8gYXRROuUYTtcMNa86wh7OVDmvwVmFioRcR58UWBRoO1XQexTtOQq_t8KYsrPZhb9gkyW8x2bAQF-d0J0EJY8JslaH6n4RBaZISww"); - Consumer messageReadToken = (http) -> http.setBearerAuth("eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQiLCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgUOBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwINafU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_QlR44vmRqS5ncrF-1R0EGcPX49U6A"); - - @Autowired - private WebTestClient rest; - - - @Test - public void getWhenValidBearerTokenThenAllows() { - - this.rest.get().uri("/") - .headers(this.noScopesToken) - .exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("Hello, subject!"); - } - - @Test - public void getWhenValidBearerTokenThenScopedRequestsAlsoWork() { - - this.rest.get().uri("/message") - .headers(this.messageReadToken) - .exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("secret message"); - } - - @Test - public void getWhenInsufficientlyScopedBearerTokenThenDeniesScopedMethodAccess() { - - this.rest.get().uri("/message") - .headers(this.noScopesToken) - .exchange() - .expectStatus().isForbidden() - .expectHeader().value(HttpHeaders.WWW_AUTHENTICATE, containsString("Bearer error=\"insufficient_scope\"")); - } -} diff --git a/samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java b/samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java deleted file mode 100644 index 62f91d1a1f..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.boot.SpringApplication; -import org.springframework.core.env.ConfigurableEnvironment; - -/** - * @author Rob Winch - */ -public class MockWebServerEnvironmentPostProcessor - implements EnvironmentPostProcessor, DisposableBean { - - private final MockWebServerPropertySource propertySource = new MockWebServerPropertySource(); - - @Override - public void postProcessEnvironment(ConfigurableEnvironment environment, - SpringApplication application) { - environment.getPropertySources().addFirst(this.propertySource); - } - - @Override - public void destroy() throws Exception { - this.propertySource.destroy(); - } -} diff --git a/samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java b/samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java deleted file mode 100644 index 54dc2ca143..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import okhttp3.mockwebserver.Dispatcher; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.core.env.PropertySource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - -import java.io.IOException; - -/** - * @author Rob Winch - */ -public class MockWebServerPropertySource extends PropertySource implements - DisposableBean { - - private static final MockResponse JWKS_RESPONSE = response( - "{\"keys\":[{\"p\":\"2p-ViY7DE9ZrdWQb544m0Jp7Cv03YCSljqfim9pD4ALhObX0OrAznOiowTjwBky9JGffMwDBVSfJSD9TSU7aH2sbbfi0bZLMdekKAuimudXwUqPDxrrg0BCyvCYgLmKjbVT3zcdylWSog93CNTxGDPzauu-oc0XPNKCXnaDpNvE\",\"kty\":\"RSA\",\"q\":\"sP_QYavrpBvSJ86uoKVGj2AGl78CSsAtpf1ybSY5TwUlorXSdqapRbY69Y271b0aMLzlleUn9ZTBO1dlKV2_dw_lPADHVia8z3pxL-8sUhIXLsgj4acchMk4c9YX-sFh07xENnyZ-_TXm3llPLuL67HUfBC2eKe800TmCYVWc9U\",\"d\":\"bn1nFxCQT4KLTHqo8mo9HvHD0cRNRNdWcKNnnEQkCF6tKbt-ILRyQGP8O40axLd7CoNVG9c9p_-g4-2kwCtLJNv_STLtwfpCY7VN5o6-ZIpfTjiW6duoPrLWq64Hm_4LOBQTiZfUPcLhsuJRHbWqakj-kV_YbUyC2Ocf_dd8IAQcSrAU2SCcDebhDCWwRUFvaa9V5eq0851S9goaA-AJz-JXyePH6ZFr8JxmWkWxYZ5kdcMD-sm9ZbxE0CaEk32l4fE4hR-L8x2dDtjWA-ahKCZ091z-gV3HWtR2JOjvxoNRjxUo3UxaGiFJHWNIl0EYUJZu1Cb-5wIlEI7wPx5mwQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"qi\":\"qS0OK48M2CIAA6_4Wdw4EbCaAfcTLf5Oy9t5BOF_PFUKqoSpZ6JsT5H0a_4zkjt-oI969v78OTlvBKbmEyKO-KeytzHBAA5CsLmVcz0THrMSg6oXZqu66MPnvWoZN9FEN5TklPOvBFm8Bg1QZ3k-YMVaM--DLvhaYR95_mqaz50\",\"dp\":\"Too2NozLGD1XrXyhabZvy1E0EuaVFj0UHQPDLSpkZ_2g3BK6Art6T0xmE8RYtmqrKIEIdlI3IliAvyvAx_1D7zWTTRaj-xlZyqJFrnXWL7zj8UxT8PkB-r2E-ILZ3NAi1gxIWezlBTZ8M6NfObDFmbTc_3tJkN_raISo8z_ziIE\",\"dq\":\"U0yhSkY5yOsa9YcMoigGVBWSJLpNHtbg5NypjHrPv8OhWbkOSq7WvSstBkFk5AtyFvvfZLMLIkWWxxGzV0t6f1MoxBtttLrYYyCxwihiiGFhLbAdSuZ1wnxcqA9bC7UVECvrQmVTpsMs8UupfHKbQBpZ8OWAqrnuYNNtG4_4Bt0\",\"n\":\"lygtuZj0lJjqOqIWocF8Bb583QDdq-aaFg8PesOp2-EDda6GqCpL-_NZVOflNGX7XIgjsWHcPsQHsV9gWuOzSJ0iEuWvtQ6eGBP5M6m7pccLNZfwUse8Cb4Ngx3XiTlyuqM7pv0LPyppZusfEHVEdeelou7Dy9k0OQ_nJTI3b2E1WBoHC58CJ453lo4gcBm1efURN3LIVc1V9NQY_ESBKVdwqYyoJPEanURLVGRd6cQKn6YrCbbIRHjqAyqOE-z3KmgDJnPriljfR5XhSGyM9eqD9Xpy6zu_MAeMJJfSArp857zLPk-Wf5VP9STAcjyfdBIybMKnwBYr2qHMT675hQ\"}]}", - 200 - ); - - private static final MockResponse NOT_FOUND_RESPONSE = response( - "{ \"message\" : \"This mock authorization server responds to just one request: GET /.well-known/jwks.json.\" }", - 404 - ); - - /** - * Name of the random {@link PropertySource}. - */ - public static final String MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME = "mockwebserver"; - - private static final String NAME = "mockwebserver.url"; - - private static final Log logger = LogFactory.getLog(MockWebServerPropertySource.class); - - private boolean started; - - public MockWebServerPropertySource() { - super(MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME, new MockWebServer()); - } - - @Override - public Object getProperty(String name) { - if (!name.equals(NAME)) { - return null; - } - if (logger.isTraceEnabled()) { - logger.trace("Looking up the url for '" + name + "'"); - } - String url = getUrl(); - return url; - } - - @Override - public void destroy() throws Exception { - getSource().shutdown(); - } - - /** - * Get's the URL (i.e. "http://localhost:123456") - * @return - */ - private String getUrl() { - MockWebServer mockWebServer = getSource(); - if (!this.started) { - intializeMockWebServer(mockWebServer); - } - String url = mockWebServer.url("").url().toExternalForm(); - return url.substring(0, url.length() - 1); - } - - private void intializeMockWebServer(MockWebServer mockWebServer) { - Dispatcher dispatcher = new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest request) { - if ("/.well-known/jwks.json".equals(request.getPath())) { - return JWKS_RESPONSE; - } - - return NOT_FOUND_RESPONSE; - } - }; - - mockWebServer.setDispatcher(dispatcher); - try { - mockWebServer.start(); - this.started = true; - } catch (IOException e) { - throw new RuntimeException("Could not start " + mockWebServer, e); - } - } - - private static MockResponse response(String body, int status) { - return new MockResponse() - .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .setResponseCode(status) - .setBody(body); - } - -} diff --git a/samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/package-info.java b/samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/package-info.java deleted file mode 100644 index 0226037822..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/main/java/org/springframework/boot/env/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This provides integration of a {@link okhttp3.mockwebserver.MockWebServer} and the - * {@link org.springframework.core.env.Environment} - * @author Rob Winch - */ -package org.springframework.boot.env; diff --git a/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/OAuth2ResourceServerController.java b/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/OAuth2ResourceServerController.java deleted file mode 100644 index ea34b99e20..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/OAuth2ResourceServerController.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Josh Cummings - */ -@RestController -public class OAuth2ResourceServerController { - - @GetMapping("/") - public String index(@AuthenticationPrincipal Jwt jwt) { - return String.format("Hello, %s!", jwt.getSubject()); - } - - @GetMapping("/message") - public String message() { - return "secret message"; - } - - @PostMapping("/message") - public String createMessage(@RequestBody String message) { - return String.format("Message was created. Content: %s", message); - } -} diff --git a/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/SecurityConfig.java b/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/SecurityConfig.java deleted file mode 100644 index d4f6429b51..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/SecurityConfig.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.web.server.SecurityWebFilterChain; - -import static org.springframework.security.config.Customizer.withDefaults; - -/** - * @author Rob Winch - * @since 5.1 - */ -@EnableWebFluxSecurity -public class SecurityConfig { - - @Bean - SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - http - .authorizeExchange((exchanges) -> - exchanges - .pathMatchers(HttpMethod.GET, "/message/**").hasAuthority("SCOPE_message:read") - .pathMatchers(HttpMethod.POST, "/message/**").hasAuthority("SCOPE_message:write") - .anyExchange().authenticated() - ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .jwt(withDefaults()) - ); - return http.build(); - } -} diff --git a/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/ServerOAuth2ResourceServerApplication.java b/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/ServerOAuth2ResourceServerApplication.java deleted file mode 100644 index c3e3575e26..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/ServerOAuth2ResourceServerApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Rob Winch - */ -@SpringBootApplication -public class ServerOAuth2ResourceServerApplication { - - public static void main(String[] args) { - SpringApplication.run(ServerOAuth2ResourceServerApplication.class, args); - } -} diff --git a/samples/boot/oauth2resourceserver-webflux/src/main/resources/META-INF/spring.factories b/samples/boot/oauth2resourceserver-webflux/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 37b447c970..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=org.springframework.boot.env.MockWebServerEnvironmentPostProcessor diff --git a/samples/boot/oauth2resourceserver-webflux/src/main/resources/application.yml b/samples/boot/oauth2resourceserver-webflux/src/main/resources/application.yml deleted file mode 100644 index 2a6d127d3f..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/main/resources/application.yml +++ /dev/null @@ -1,6 +0,0 @@ -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json diff --git a/samples/boot/oauth2resourceserver-webflux/src/test/java/sample/OAuth2ResourceServerControllerTests.java b/samples/boot/oauth2resourceserver-webflux/src/test/java/sample/OAuth2ResourceServerControllerTests.java deleted file mode 100644 index 8fc72574f1..0000000000 --- a/samples/boot/oauth2resourceserver-webflux/src/test/java/sample/OAuth2ResourceServerControllerTests.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; -import reactor.core.publisher.Mono; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockJwt; - -/** - * @author Josh Cummings - */ -@RunWith(SpringRunner.class) -@WebFluxTest(OAuth2ResourceServerController.class) -@Import(SecurityConfig.class) -public class OAuth2ResourceServerControllerTests { - - @Autowired - WebTestClient rest; - - @MockBean - ReactiveJwtDecoder jwtDecoder; - - @Test - public void indexGreetsAuthenticatedUser() { - this.rest.mutateWith(mockJwt().jwt((jwt) -> jwt.subject("test-subject"))) - .get().uri("/").exchange() - .expectBody(String.class).isEqualTo("Hello, test-subject!"); - } - - @Test - public void messageCanBeReadWithScopeMessageReadAuthority() { - this.rest.mutateWith(mockJwt().jwt((jwt) -> jwt.claim("scope", "message:read"))) - .get().uri("/message").exchange() - .expectBody(String.class).isEqualTo("secret message"); - - this.rest.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("SCOPE_message:read"))) - .get().uri("/message").exchange() - .expectBody(String.class).isEqualTo("secret message"); - } - - @Test - public void messageCanNotBeReadWithoutScopeMessageReadAuthority() { - this.rest.mutateWith(mockJwt()) - .get().uri("/message").exchange() - .expectStatus().isForbidden(); - } - - @Test - public void messageCanNotBeCreatedWithoutAnyScope() { - Jwt jwt = jwt().claim("scope", "").build(); - when(this.jwtDecoder.decode(anyString())).thenReturn(Mono.just(jwt)); - this.rest.post().uri("/message") - .headers((headers) -> headers.setBearerAuth(jwt.getTokenValue())) - .syncBody("Hello message").exchange() - .expectStatus().isForbidden(); - } - - @Test - public void messageCanNotBeCreatedWithScopeMessageReadAuthority() { - Jwt jwt = jwt().claim("scope", "message:read").build(); - when(this.jwtDecoder.decode(anyString())).thenReturn(Mono.just(jwt)); - this.rest.post().uri("/message") - .headers((headers) -> headers.setBearerAuth(jwt.getTokenValue())) - .syncBody("Hello message").exchange() - .expectStatus().isForbidden(); - } - - @Test - public void messageCanBeCreatedWithScopeMessageWriteAuthority() { - Jwt jwt = jwt().claim("scope", "message:write").build(); - when(this.jwtDecoder.decode(anyString())).thenReturn(Mono.just(jwt)); - this.rest.post().uri("/message") - .headers((headers) -> headers.setBearerAuth(jwt.getTokenValue())) - .syncBody("Hello message").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("Message was created. Content: Hello message"); - } - - private Jwt.Builder jwt() { - return Jwt.withTokenValue("token").header("alg", "none"); - } -} diff --git a/samples/boot/oauth2resourceserver/README.adoc b/samples/boot/oauth2resourceserver/README.adoc deleted file mode 100644 index a82747004f..0000000000 --- a/samples/boot/oauth2resourceserver/README.adoc +++ /dev/null @@ -1,126 +0,0 @@ -= OAuth 2.0 Resource Server Sample - -This sample demonstrates integrating Resource Server with a mock Authorization Server, though it can be modified to integrate -with your favorite Authorization Server. - -With it, you can run the integration tests or run the application as a stand-alone service to explore how you can -secure your own service with OAuth 2.0 Bearer Tokens using Spring Security. - -== 1. Running the tests - -To run the tests, do: - -```bash -./gradlew integrationTest -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplicationTests` from there. - -=== What is it doing? - -By default, the tests are pointing at a mock Authorization Server instance. - -The tests are configured with a set of hard-coded tokens originally obtained from the mock Authorization Server, -and each makes a query to the Resource Server with their corresponding token. - -The Resource Server subsquently verifies with the Authorization Server and authorizes the request, returning the phrase - -```bash -Hello, subject! -``` - -where "subject" is the value of the `sub` field in the JWT returned by the Authorization Server. - -== 2. Running the app - -To run as a stand-alone application, do: - -```bash -./gradlew bootRun -``` - -Or import the project into your IDE and run `OAuth2ResourceServerApplication` from there. - -Once it is up, you can use the following token: - -```bash -export TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjoyMTY0MjQ1ODgwLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiMDFkOThlZWEtNjc0MC00OGRlLTk4ODAtYzM5ZjgyMGZiNzVlIiwiY2xpZW50X2lkIjoibm9zY29wZXMiLCJzY29wZSI6WyJub25lIl19.VOzgGLOUuQ_R2Ur1Ke41VaobddhKgUZgto7Y3AGxst7SuxLQ4LgWwdSSDRx-jRvypjsCgYPbjAYLhn9nCbfwtCitkymUKUNKdebvVAI0y8YvliWTL5S-GiJD9dN8SSsXUla9A4xB_9Mt5JAlRpQotQSCLojVSKQmjhMpQWmYAlKVjnlImoRwQFPI4w3Ijn4G4EMTKWUYRfrD0-WNT9ZYWBeza6QgV6sraP7ToRB3eQLy2p04cU40X-RHLeYCsMBfxsMMh89CJff-9tn7VDKi1hAGc_Lp9yS9ZaItJuFJTjf8S_vsjVB1nBhvdS_6IED_m_fOU52KiGSO2qL6shxHvg -``` - -And then make this request: - -```bash -curl -H "Authorization: Bearer $TOKEN" localhost:8080 -``` - -Which will respond with the phrase: - -```bash -Hello, subject! -``` - -where `subject` is the value of the `sub` field in the JWT returned by the Authorization Server. - -Or this to make a GET request to /messages: - -```bash -export TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjoyMTY0MjQ1NjQ4LCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiY2I1ZGMwNDYtMDkyMi00ZGJmLWE5MzAtOGI2M2FhZTYzZjk2IiwiY2xpZW50X2lkIjoicmVhZGVyIiwic2NvcGUiOlsibWVzc2FnZTpyZWFkIl19.Pre2ksnMiOGYWQtuIgHB0i3uTnNzD0SMFM34iyQJHK5RLlSjge08s9qHdx6uv5cZ4gZm_cB1D6f4-fLx76bCblK6mVcabbR74w_eCdSBXNXuqG-HNrOYYmmx5iJtdwx5fXPmF8TyVzsq_LvRm_LN4lWNYquT4y36Tox6ZD3feYxXvHQ3XyZn9mVKnlzv-GCwkBohCR3yPow5uVmr04qh_al52VIwKMrvJBr44igr4fTZmzwRAZmQw5rZeyep0b4nsCjadNcndHtMtYKNVuG5zbDLsB7GGvilcI9TDDnUXtwthB_3iq32DAd9x8wJmJ5K8gmX6GjZFtYzKk_zEboXoQ - -curl -H "Authorization: Bearer $TOKEN" localhost:8080/message -``` - -Will respond with: - -```bash -secret message -``` - -In order to make a POST request to /message, you can use the following request: - -```bash -export TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjoyMTY0MjQzOTA0LCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiZGI4ZjgwMzQtM2VlNy00NjBjLTk3NTEtMDJiMDA1OWI5NzA4IiwiY2xpZW50X2lkIjoid3JpdGVyIiwic2NvcGUiOlsibWVzc2FnZTp3cml0ZSJdfQ.USvpx_ntKXtchLmc93auJq0qSav6vLm4B7ItPzhrDH2xmogBP35eKeklwXK5GCb7ck1aKJV5SpguBlTCz0bZC1zAWKB6gyFIqedALPAran5QR-8WpGfl0wFqds7d8Jw3xmpUUBduRLab9hkeAhgoVgxevc8d6ITM7kRnHo5wT3VzvBU8DquedVXm5fbBnRPgG4_jOWJKbqYpqaR2z2TnZRWh3CqL82Orh1Ww1dJYF_fae1dTVV4tvN5iSndYcGxMoBaiw3kRRi6EyNxnXnt1pFtZqc1f6D9x4AHiri8_vpBp2vwG5OfQD5-rrleP_XlIB3rNQT7tu3fiqu4vUzQaEg - -curl -H "Authorization: Bearer $TOKEN" -d "my message" localhost:8080/message -``` - -Will respond this: - -```bash -Message was created. Content: my message -``` - -== 2. Testing against other Authorization Servers - -_In order to use this sample, your Authorization Server must support JWTs that either use the "scope" or "scp" attribute._ - -To change the sample to point at your Authorization Server, simply find this property in the `application.yml`: - -```yaml -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json -``` - -And change the property to your Authorization Server's JWK set endpoint: - -```yaml -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: https://dev-123456.oktapreview.com/oauth2/default/v1/keys -``` - -And then you can run the app the same as before: - -```bash -./gradlew bootRun -``` - -Make sure to obtain valid tokens from your Authorization Server in order to play with the sample Resource Server. -To use the `/` endpoint, any valid token from your Authorization Server will do. -To use the `/message` endpoint, the token should have the `message:read` scope. diff --git a/samples/boot/oauth2resourceserver/spring-security-samples-boot-oauth2resourceserver.gradle b/samples/boot/oauth2resourceserver/spring-security-samples-boot-oauth2resourceserver.gradle deleted file mode 100644 index 2135bb0af6..0000000000 --- a/samples/boot/oauth2resourceserver/spring-security-samples-boot-oauth2resourceserver.gradle +++ /dev/null @@ -1,13 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-jose') - compile project(':spring-security-oauth2-resource-server') - - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'com.squareup.okhttp3:mockwebserver' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/oauth2resourceserver/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java b/samples/boot/oauth2resourceserver/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java deleted file mode 100644 index bb7de58665..0000000000 --- a/samples/boot/oauth2resourceserver/src/integration-test/java/sample/OAuth2ResourceServerApplicationITests.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.RequestPostProcessor; - -import static org.hamcrest.Matchers.containsString; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * Integration tests for {@link OAuth2ResourceServerApplication} - * - * @author Josh Cummings - */ -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -@ActiveProfiles("test") -public class OAuth2ResourceServerApplicationITests { - - String noScopesToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjoyMTY0MjQ1ODgwLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiMDFkOThlZWEtNjc0MC00OGRlLTk4ODAtYzM5ZjgyMGZiNzVlIiwiY2xpZW50X2lkIjoibm9zY29wZXMiLCJzY29wZSI6WyJub25lIl19.VOzgGLOUuQ_R2Ur1Ke41VaobddhKgUZgto7Y3AGxst7SuxLQ4LgWwdSSDRx-jRvypjsCgYPbjAYLhn9nCbfwtCitkymUKUNKdebvVAI0y8YvliWTL5S-GiJD9dN8SSsXUla9A4xB_9Mt5JAlRpQotQSCLojVSKQmjhMpQWmYAlKVjnlImoRwQFPI4w3Ijn4G4EMTKWUYRfrD0-WNT9ZYWBeza6QgV6sraP7ToRB3eQLy2p04cU40X-RHLeYCsMBfxsMMh89CJff-9tn7VDKi1hAGc_Lp9yS9ZaItJuFJTjf8S_vsjVB1nBhvdS_6IED_m_fOU52KiGSO2qL6shxHvg"; - String messageReadToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjoyMTY0MjQ1NjQ4LCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiY2I1ZGMwNDYtMDkyMi00ZGJmLWE5MzAtOGI2M2FhZTYzZjk2IiwiY2xpZW50X2lkIjoicmVhZGVyIiwic2NvcGUiOlsibWVzc2FnZTpyZWFkIl19.Pre2ksnMiOGYWQtuIgHB0i3uTnNzD0SMFM34iyQJHK5RLlSjge08s9qHdx6uv5cZ4gZm_cB1D6f4-fLx76bCblK6mVcabbR74w_eCdSBXNXuqG-HNrOYYmmx5iJtdwx5fXPmF8TyVzsq_LvRm_LN4lWNYquT4y36Tox6ZD3feYxXvHQ3XyZn9mVKnlzv-GCwkBohCR3yPow5uVmr04qh_al52VIwKMrvJBr44igr4fTZmzwRAZmQw5rZeyep0b4nsCjadNcndHtMtYKNVuG5zbDLsB7GGvilcI9TDDnUXtwthB_3iq32DAd9x8wJmJ5K8gmX6GjZFtYzKk_zEboXoQ"; - String messageWriteToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiZXhwIjoyMTY0MjQzOTA0LCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiZGI4ZjgwMzQtM2VlNy00NjBjLTk3NTEtMDJiMDA1OWI5NzA4IiwiY2xpZW50X2lkIjoid3JpdGVyIiwic2NvcGUiOlsibWVzc2FnZTp3cml0ZSJdfQ.USvpx_ntKXtchLmc93auJq0qSav6vLm4B7ItPzhrDH2xmogBP35eKeklwXK5GCb7ck1aKJV5SpguBlTCz0bZC1zAWKB6gyFIqedALPAran5QR-8WpGfl0wFqds7d8Jw3xmpUUBduRLab9hkeAhgoVgxevc8d6ITM7kRnHo5wT3VzvBU8DquedVXm5fbBnRPgG4_jOWJKbqYpqaR2z2TnZRWh3CqL82Orh1Ww1dJYF_fae1dTVV4tvN5iSndYcGxMoBaiw3kRRi6EyNxnXnt1pFtZqc1f6D9x4AHiri8_vpBp2vwG5OfQD5-rrleP_XlIB3rNQT7tu3fiqu4vUzQaEg"; - - @Autowired - MockMvc mvc; - - @Test - public void performWhenValidBearerTokenThenAllows() - throws Exception { - - this.mvc.perform(get("/").with(bearerToken(this.noScopesToken))) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("Hello, subject!"))); - } - - @Test - public void performWhenValidBearerTokenThenScopedRequestsAlsoWork() - throws Exception { - - this.mvc.perform(get("/message").with(bearerToken(this.messageReadToken))) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("secret message"))); - } - - @Test - public void performWhenInsufficientlyScopedBearerTokenThenDeniesScopedMethodAccess() - throws Exception { - - this.mvc.perform(get("/message").with(bearerToken(this.noScopesToken))) - .andExpect(status().isForbidden()) - .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, - containsString("Bearer error=\"insufficient_scope\""))); - } - - @Test - public void performPostWhenValidBearerTokenThenScopedRequestsAlsoWork() - throws Exception { - - this.mvc.perform(post("/message").content("example message") - .with(bearerToken(this.messageWriteToken))) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("Message was created"))); - } - - @Test - public void performPostWhenInsufficientlyScopedBearerTokenThenDeniesScopedMethodAccess() - throws Exception { - - this.mvc.perform(post("/message").content("Example message") - .with(bearerToken(this.messageReadToken))) - .andExpect(status().isForbidden()) - .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, - containsString("Bearer error=\"insufficient_scope\""))); - } - - private static class BearerTokenRequestPostProcessor implements RequestPostProcessor { - private String token; - - BearerTokenRequestPostProcessor(String token) { - this.token = token; - } - - @Override - public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { - request.addHeader("Authorization", "Bearer " + this.token); - return request; - } - } - - private static BearerTokenRequestPostProcessor bearerToken(String token) { - return new BearerTokenRequestPostProcessor(token); - } -} diff --git a/samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java b/samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java deleted file mode 100644 index 62f91d1a1f..0000000000 --- a/samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/MockWebServerEnvironmentPostProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.boot.SpringApplication; -import org.springframework.core.env.ConfigurableEnvironment; - -/** - * @author Rob Winch - */ -public class MockWebServerEnvironmentPostProcessor - implements EnvironmentPostProcessor, DisposableBean { - - private final MockWebServerPropertySource propertySource = new MockWebServerPropertySource(); - - @Override - public void postProcessEnvironment(ConfigurableEnvironment environment, - SpringApplication application) { - environment.getPropertySources().addFirst(this.propertySource); - } - - @Override - public void destroy() throws Exception { - this.propertySource.destroy(); - } -} diff --git a/samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java b/samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java deleted file mode 100644 index b90ad29b91..0000000000 --- a/samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/MockWebServerPropertySource.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.env; - -import okhttp3.mockwebserver.Dispatcher; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.core.env.PropertySource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - -import java.io.IOException; - -/** - * @author Rob Winch - */ -public class MockWebServerPropertySource extends PropertySource implements - DisposableBean { - - private static final MockResponse JWKS_RESPONSE = response( - "{ \"keys\": [ { \"kty\": \"RSA\", \"e\": \"AQAB\", \"n\": \"jvBtqsGCOmnYzwe_-HvgOqlKk6HPiLEzS6uCCcnVkFXrhnkPMZ-uQXTR0u-7ZklF0XC7-AMW8FQDOJS1T7IyJpCyeU4lS8RIf_Z8RX51gPGnQWkRvNw61RfiSuSA45LR5NrFTAAGoXUca_lZnbqnl0td-6hBDVeHYkkpAsSck1NPhlcsn-Pvc2Vleui_Iy1U2mzZCM1Vx6Dy7x9IeP_rTNtDhULDMFbB_JYs-Dg6Zd5Ounb3mP57tBGhLYN7zJkN1AAaBYkElsc4GUsGsUWKqgteQSXZorpf6HdSJsQMZBDd7xG8zDDJ28hGjJSgWBndRGSzQEYU09Xbtzk-8khPuw\" } ] }", - 200 - ); - - private static final MockResponse NOT_FOUND_RESPONSE = response( - "{ \"message\" : \"This mock authorization server responds to just one request: GET /.well-known/jwks.json.\" }", - 404 - ); - - /** - * Name of the random {@link PropertySource}. - */ - public static final String MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME = "mockwebserver"; - - private static final String NAME = "mockwebserver.url"; - - private static final Log logger = LogFactory.getLog(MockWebServerPropertySource.class); - - private boolean started; - - public MockWebServerPropertySource() { - super(MOCK_WEB_SERVER_PROPERTY_SOURCE_NAME, new MockWebServer()); - } - - @Override - public Object getProperty(String name) { - if (!name.equals(NAME)) { - return null; - } - if (logger.isTraceEnabled()) { - logger.trace("Looking up the url for '" + name + "'"); - } - String url = getUrl(); - return url; - } - - @Override - public void destroy() throws Exception { - getSource().shutdown(); - } - - /** - * Get's the URL (i.e. "http://localhost:123456") - * @return - */ - private String getUrl() { - MockWebServer mockWebServer = getSource(); - if (!this.started) { - intializeMockWebServer(mockWebServer); - } - String url = mockWebServer.url("").url().toExternalForm(); - return url.substring(0, url.length() - 1); - } - - private void intializeMockWebServer(MockWebServer mockWebServer) { - Dispatcher dispatcher = new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest request) { - if ("/.well-known/jwks.json".equals(request.getPath())) { - return JWKS_RESPONSE; - } - - return NOT_FOUND_RESPONSE; - } - }; - - mockWebServer.setDispatcher(dispatcher); - try { - mockWebServer.start(); - this.started = true; - } catch (IOException e) { - throw new RuntimeException("Could not start " + mockWebServer, e); - } - } - - private static MockResponse response(String body, int status) { - return new MockResponse() - .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .setResponseCode(status) - .setBody(body); - } - -} diff --git a/samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/package-info.java b/samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/package-info.java deleted file mode 100644 index 0226037822..0000000000 --- a/samples/boot/oauth2resourceserver/src/main/java/org/springframework/boot/env/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This provides integration of a {@link okhttp3.mockwebserver.MockWebServer} and the - * {@link org.springframework.core.env.Environment} - * @author Rob Winch - */ -package org.springframework.boot.env; diff --git a/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerApplication.java b/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerApplication.java deleted file mode 100644 index a0841c00f3..0000000000 --- a/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Josh Cummings - */ -@SpringBootApplication -public class OAuth2ResourceServerApplication { - - public static void main(String[] args) { - SpringApplication.run(OAuth2ResourceServerApplication.class, args); - } -} diff --git a/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerController.java b/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerController.java deleted file mode 100644 index c761078dd8..0000000000 --- a/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerController.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Josh Cummings - */ -@RestController -public class OAuth2ResourceServerController { - - @GetMapping("/") - public String index(@AuthenticationPrincipal Jwt jwt) { - return String.format("Hello, %s!", jwt.getSubject()); - } - - @GetMapping("/message") - public String message() { - return "secret message"; - } - - @PostMapping("/message") - public String createMessage(@RequestBody String message) { - return String.format("Message was created. Content: %s", message); - } -} diff --git a/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java deleted file mode 100644 index d7e157cfc6..0000000000 --- a/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; -import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; - -/** - * @author Josh Cummings - */ -@EnableWebSecurity -public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter { - - @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}") String jwkSetUri; - - @Override - protected void configure(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeRequests((authorizeRequests) -> - authorizeRequests - .antMatchers(HttpMethod.GET, "/message/**").hasAuthority("SCOPE_message:read") - .antMatchers(HttpMethod.POST, "/message/**").hasAuthority("SCOPE_message:write") - .anyRequest().authenticated() - ) - .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); - // @formatter:on - } - - @Bean - JwtDecoder jwtDecoder() { - return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri).build(); - } -} diff --git a/samples/boot/oauth2resourceserver/src/main/resources/META-INF/spring.factories b/samples/boot/oauth2resourceserver/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 37b447c970..0000000000 --- a/samples/boot/oauth2resourceserver/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=org.springframework.boot.env.MockWebServerEnvironmentPostProcessor diff --git a/samples/boot/oauth2resourceserver/src/main/resources/application.yml b/samples/boot/oauth2resourceserver/src/main/resources/application.yml deleted file mode 100644 index 2a6d127d3f..0000000000 --- a/samples/boot/oauth2resourceserver/src/main/resources/application.yml +++ /dev/null @@ -1,6 +0,0 @@ -spring: - security: - oauth2: - resourceserver: - jwt: - jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json diff --git a/samples/boot/oauth2resourceserver/src/test/java/sample/OAuth2ResourceServerControllerTests.java b/samples/boot/oauth2resourceserver/src/test/java/sample/OAuth2ResourceServerControllerTests.java deleted file mode 100644 index 565212b073..0000000000 --- a/samples/boot/oauth2resourceserver/src/test/java/sample/OAuth2ResourceServerControllerTests.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.hamcrest.CoreMatchers.is; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * - * @author Jérôme Wacongne <ch4mp@c4-soft.com> - * @author Josh Cummings - * @since 5.2.0 - * - */ -@RunWith(SpringRunner.class) -@WebMvcTest(OAuth2ResourceServerController.class) -public class OAuth2ResourceServerControllerTests { - - @Autowired - MockMvc mockMvc; - - @Test - public void indexGreetsAuthenticatedUser() throws Exception { - mockMvc.perform(get("/").with(jwt().jwt((jwt) -> jwt.subject("ch4mpy")))) - .andExpect(content().string(is("Hello, ch4mpy!"))); - } - - @Test - public void messageCanBeReadWithScopeMessageReadAuthority() throws Exception { - mockMvc.perform(get("/message").with(jwt().jwt((jwt) -> jwt.claim("scope", "message:read")))) - .andExpect(content().string(is("secret message"))); - - mockMvc.perform(get("/message") - .with(jwt().authorities(new SimpleGrantedAuthority(("SCOPE_message:read"))))) - .andExpect(content().string(is("secret message"))); - } - - @Test - public void messageCanNotBeReadWithoutScopeMessageReadAuthority() throws Exception { - mockMvc.perform(get("/message").with(jwt())) - .andExpect(status().isForbidden()); - } - - @Test - public void messageCanNotBeCreatedWithoutAnyScope() throws Exception { - mockMvc.perform(post("/message") - .content("Hello message") - .with(jwt())) - .andExpect(status().isForbidden()); - } - - @Test - public void messageCanNotBeCreatedWithScopeMessageReadAuthority() throws Exception { - mockMvc.perform(post("/message") - .content("Hello message") - .with(jwt().jwt((jwt) -> jwt.claim("scope", "message:read")))) - .andExpect(status().isForbidden()); - } - - @Test - public void messageCanBeCreatedWithScopeMessageWriteAuthority() - throws Exception { - mockMvc.perform(post("/message") - .content("Hello message") - .with(jwt().jwt((jwt) -> jwt.claim("scope", "message:write")))) - .andExpect(status().isOk()) - .andExpect(content().string(is("Message was created. Content: Hello message"))); - } -} diff --git a/samples/boot/oauth2webclient-webflux/README.adoc b/samples/boot/oauth2webclient-webflux/README.adoc deleted file mode 100644 index ea984aa684..0000000000 --- a/samples/boot/oauth2webclient-webflux/README.adoc +++ /dev/null @@ -1,63 +0,0 @@ -= OAuth 2.0 WebClient (WebFlux) Sample - -== GitHub Repositories - -This guide provides instructions on setting up the sample application, which leverages WebClient OAuth2 integration to display a list of public GitHub repositories that are accessible to the authenticated user. - -This includes repositories owned by the authenticated user, repositories where the authenticated user is a collaborator, and repositories that the authenticated user has access to through an organization membership. - -The following sections provide detailed steps for setting up the sample and covers the following topics: - -* <> -* <> -* <> - -[[github-register-application]] -=== Register OAuth application - -To use GitHub's OAuth 2.0 authorization system, you must https://github.com/settings/applications/new[Register a new OAuth application]. - -When registering the OAuth application, ensure the *Authorization callback URL* is set to `http://localhost:8080/login/oauth2/code/client-id`. - -The Authorization callback URL (redirect URI) is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with GitHub and have granted access to the OAuth application on the _Authorize application_ page. - -[[github-application-config]] -=== Configure application.yml - -Now that you have a new OAuth application with GitHub, you need to configure the sample to use the OAuth application for the _authorization code grant flow_. -To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - client-id: <2> - client-id: replace-with-client-id - client-secret: replace-with-client-secret - provider: github - scope: read:user,public_repo ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, which is github. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. - -[[github-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ form login page. -Log in using *'user'* (username) and *'password'* (password) or click the link to authenticate with GitHub and then you'll be redirected to GitHub for authentication. - -After authenticating with your GitHub credentials, the next page presented to you is "Authorize application". -This page will ask you to *Authorize* the application you created in the previous step. -Click _Authorize application_ to allow the OAuth application to access and display your public repository information. diff --git a/samples/boot/oauth2webclient-webflux/spring-security-samples-boot-oauth2webclient-webflux.gradle b/samples/boot/oauth2webclient-webflux/spring-security-samples-boot-oauth2webclient-webflux.gradle deleted file mode 100644 index 286f80a581..0000000000 --- a/samples/boot/oauth2webclient-webflux/spring-security-samples-boot-oauth2webclient-webflux.gradle +++ /dev/null @@ -1,15 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-client') - compile project(':spring-security-oauth2-jose') - compile 'org.springframework.boot:spring-boot-starter-thymeleaf' - compile 'org.springframework.boot:spring-boot-starter-webflux' - compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' - compile 'io.projectreactor.netty:reactor-netty' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' - testCompile 'com.squareup.okhttp3:mockwebserver' -} diff --git a/samples/boot/oauth2webclient-webflux/src/main/java/sample/OAuth2WebClientWebFluxApplication.java b/samples/boot/oauth2webclient-webflux/src/main/java/sample/OAuth2WebClientWebFluxApplication.java deleted file mode 100644 index cdd6416f93..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/main/java/sample/OAuth2WebClientWebFluxApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Joe Grandja - */ -@SpringBootApplication -public class OAuth2WebClientWebFluxApplication { - - public static void main(String[] args) { - SpringApplication.run(OAuth2WebClientWebFluxApplication.class, args); - } -} diff --git a/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/SecurityConfig.java b/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/SecurityConfig.java deleted file mode 100644 index 33fb8b7867..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/SecurityConfig.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.web.server.SecurityWebFilterChain; - -import static org.springframework.security.config.Customizer.withDefaults; - -/** - * @author Rob Winch - */ -@EnableWebFluxSecurity -public class SecurityConfig { - - @Bean - SecurityWebFilterChain configure(ServerHttpSecurity http) { - http - .authorizeExchange((exchanges) -> - exchanges - .pathMatchers("/", "/public/**").permitAll() - .anyExchange().authenticated() - ) - .oauth2Login(withDefaults()) - .formLogin(withDefaults()) - .oauth2Client(withDefaults()); - return http.build(); - } - - @Bean - MapReactiveUserDetailsService userDetailsService() { - UserDetails userDetails = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("USER") - .build(); - return new MapReactiveUserDetailsService(userDetails); - } -} diff --git a/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/WebClientConfig.java b/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/WebClientConfig.java deleted file mode 100644 index 6016aa2ef5..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/WebClientConfig.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.config; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProvider; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProviderBuilder; -import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; -import org.springframework.security.oauth2.client.web.DefaultReactiveOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; -import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; -import org.springframework.web.reactive.function.client.WebClient; - -/** - * @author Rob Winch - * @since 5.1 - */ -@Configuration -public class WebClientConfig { - - @Value("${resource-uri}") String uri; - - @Bean - WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) { - ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = - new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); - oauth.setDefaultOAuth2AuthorizedClient(true); - return WebClient.builder() - .baseUrl(this.uri) - .filter(oauth) - .build(); - } - - @Bean - ReactiveOAuth2AuthorizedClientManager authorizedClientManager( - ReactiveClientRegistrationRepository clientRegistrationRepository, - ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { - - ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = - ReactiveOAuth2AuthorizedClientProviderBuilder.builder() - .authorizationCode() - .refreshToken() - .clientCredentials() - .password() - .build(); - DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager = - new DefaultReactiveOAuth2AuthorizedClientManager( - clientRegistrationRepository, authorizedClientRepository); - authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); - - return authorizedClientManager; - } -} diff --git a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/IndexController.java b/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/IndexController.java deleted file mode 100644 index e1e0035ef1..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/IndexController.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.web; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; - -/** - * @author Rob Winch - */ -@Controller -public class IndexController { - @GetMapping("/") - String index() { - return "index"; - } -} diff --git a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/OAuth2WebClientController.java b/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/OAuth2WebClientController.java deleted file mode 100644 index a1ddae90aa..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/OAuth2WebClientController.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.web; - -import reactor.core.publisher.Mono; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId; - -/** - * @author Joe Grandja - * @author Rob Winch - */ -@Controller -@RequestMapping(path = {"/webclient", "/public/webclient"}) -public class OAuth2WebClientController { - private final WebClient webClient; - - public OAuth2WebClientController(WebClient webClient) { - this.webClient = webClient; - } - - @GetMapping("/explicit") - String explicit(Model model) { - Mono body = this.webClient - .get() - .attributes(clientRegistrationId("client-id")) - .retrieve() - .bodyToMono(String.class); - model.addAttribute("body", body); - return "response"; - } - - @GetMapping("/implicit") - String implicit(Model model) { - Mono body = this.webClient - .get() - .retrieve() - .bodyToMono(String.class); - model.addAttribute("body", body); - return "response"; - } -} diff --git a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java b/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java deleted file mode 100644 index 558277394f..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.web; - -import reactor.core.publisher.Mono; - -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient; - -/** - * @author Joe Grandja - * @author Rob Winch - */ -@Controller -@RequestMapping(path = {"/annotation", "/public/annotation"}) -public class RegisteredOAuth2AuthorizedClientController { - - private final WebClient webClient; - - public RegisteredOAuth2AuthorizedClientController(WebClient webClient) { - this.webClient = webClient; - } - - @GetMapping("/explicit") - String explicit(Model model, @RegisteredOAuth2AuthorizedClient("client-id") OAuth2AuthorizedClient authorizedClient) { - Mono body = this.webClient - .get() - .attributes(oauth2AuthorizedClient(authorizedClient)) - .retrieve() - .bodyToMono(String.class); - model.addAttribute("body", body); - return "response"; - } - - @GetMapping("/implicit") - String implicit(Model model, @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient) { - Mono body = this.webClient - .get() - .attributes(oauth2AuthorizedClient(authorizedClient)) - .retrieve() - .bodyToMono(String.class); - model.addAttribute("body", body); - return "response"; - } -} diff --git a/samples/boot/oauth2webclient-webflux/src/main/resources/application.yml b/samples/boot/oauth2webclient-webflux/src/main/resources/application.yml deleted file mode 100644 index 8528a06d0d..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/main/resources/application.yml +++ /dev/null @@ -1,21 +0,0 @@ -logging: - level: - root: INFO - org.springframework.web: INFO - org.springframework.security: INFO -# org.springframework.boot.autoconfigure: DEBUG - -spring: - thymeleaf: - cache: false - security: - oauth2: - client: - registration: - client-id: - client-id: replace-with-client-id - client-secret: replace-with-client-secret - provider: github - scope: read:user,public_repo - -resource-uri: https://api.github.com/user/repos diff --git a/samples/boot/oauth2webclient-webflux/src/main/resources/templates/index.html b/samples/boot/oauth2webclient-webflux/src/main/resources/templates/index.html deleted file mode 100644 index 7787a75dd7..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/main/resources/templates/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - OAuth2 WebClient Showcase - - - -Log Out -

Examples

- -

@RegisteredOAuth2AuthorizedClient

-

-Examples on RegisteredOAuth2AuthorizedClientController -

Authenticated

-
    -
  • Explicit - Explicitly provide a Client Registration Id
  • -
  • - Implicit - Use the currently logged in user's OAuth Token. This will - only work if the user authenticates with oauth2Login and the token provided is the correct token provided at - log in is authorized.
  • -
-

Public

-
    -
  • Explicit - Explicitly provide a Client Registration Id
  • -
  • - Implicit - This will fail if the user is not authenticated. - Since it is mapped to permitAll, it is going to fail unless the user already took an action to log in and then - authenticates with oauth2Login()
  • -
- -

ServerOAuth2AuthorizedClientExchangeFilterFunction

-

- Examples on OAuth2WebClientController that demonstrate how to use ServerOAuth2AuthorizedClientExchangeFilterFunction -

Authenticated

-
    -
  • Explicit - Explicitly provide a Client Registration Id
  • -
  • - Implicit - Use the currently logged in user's OAuth Token. This will - only work if the user authenticates with oauth2Login and the token provided is the correct token provided at - log in is authorized.
  • -
-

Public

-
    -
  • Explicit - Explicitly provide a Client Registration Id
  • -
  • - Implicit - This will fail if the user is not authenticated. - Since it is mapped to permitAll, it is going to fail unless the user already took an action to log in and then - authenticates with oauth2Login()
  • -
- - diff --git a/samples/boot/oauth2webclient-webflux/src/main/resources/templates/response.html b/samples/boot/oauth2webclient-webflux/src/main/resources/templates/response.html deleted file mode 100644 index 210c18c29a..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/main/resources/templates/response.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - OAuth2 WebClient Showcase - - - -Back -

Response

-
- - - diff --git a/samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientControllerTests.java b/samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientControllerTests.java deleted file mode 100644 index 52445dd212..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientControllerTests.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.junit.AfterClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import sample.config.SecurityConfig; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Client; -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Login; - -@WebFluxTest -@Import(SecurityConfig.class) -@AutoConfigureWebTestClient -@RunWith(SpringRunner.class) -public class OAuth2WebClientControllerTests { - private static MockWebServer web = new MockWebServer(); - - @Autowired - private WebTestClient client; - - @AfterClass - public static void shutdown() throws Exception { - web.shutdown(); - } - - @Test - public void explicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.client.mutateWith(mockOAuth2Login()) - .mutateWith(mockOAuth2Client("client-id")) - .get().uri("/webclient/explicit") - .exchange() - .expectStatus().isOk(); - } - - @Test - public void implicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.client.mutateWith(mockOAuth2Login()) - .get().uri("/webclient/implicit") - .exchange() - .expectStatus().isOk(); - } - - @Test - public void publicExplicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.client.mutateWith(mockOAuth2Client("client-id")) - .get().uri("/public/webclient/explicit") - .exchange() - .expectStatus().isOk(); - } - - @Test - public void publicImplicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.client.mutateWith(mockOAuth2Login()) - .get().uri("/public/webclient/implicit") - .exchange() - .expectStatus().isOk(); - } - - @TestConfiguration - static class WebClientConfig { - @Bean - WebClient web() { - return WebClient.create(web.url("/").toString()); - } - } -} diff --git a/samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientWebFluxApplicationTests.java b/samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientWebFluxApplicationTests.java deleted file mode 100644 index 657a6f7a16..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientWebFluxApplicationTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -/** - * @author Rob Winch - */ -@SpringBootTest -@AutoConfigureWebTestClient -@RunWith(SpringRunner.class) -public class OAuth2WebClientWebFluxApplicationTests { - @Autowired - private WebTestClient client; - - @Test - public void annotationExplicitWhenNotAuthenticatedThenLoginRequested() { - this.client.get().uri("/annotation/explicit") - .exchange() - .expectStatus().is3xxRedirection(); - } -} diff --git a/samples/boot/oauth2webclient-webflux/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java b/samples/boot/oauth2webclient-webflux/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java deleted file mode 100644 index 32fc9095b7..0000000000 --- a/samples/boot/oauth2webclient-webflux/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.junit.AfterClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import sample.config.SecurityConfig; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Client; -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Login; - -@WebFluxTest -@Import(SecurityConfig.class) -@AutoConfigureWebTestClient -@RunWith(SpringRunner.class) -public class RegisteredOAuth2AuthorizedClientControllerTests { - private static MockWebServer web = new MockWebServer(); - - @Autowired - private WebTestClient client; - - @AfterClass - public static void shutdown() throws Exception { - web.shutdown(); - } - - @Test - public void annotationExplicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.client.mutateWith(mockOAuth2Login()) - .mutateWith(mockOAuth2Client("client-id")) - .get().uri("/annotation/explicit") - .exchange() - .expectStatus().isOk(); - } - - @Test - public void annotationImplicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.client.mutateWith(mockOAuth2Login()) - .get().uri("/annotation/implicit") - .exchange() - .expectStatus().isOk(); - } - - @Test - public void publicAnnotationExplicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.client.mutateWith(mockOAuth2Client("client-id")) - .get().uri("/public/annotation/explicit") - .exchange() - .expectStatus().isOk(); - } - - @Test - public void publicAnnotationImplicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.client.mutateWith(mockOAuth2Login()) - .get().uri("/public/annotation/implicit") - .exchange() - .expectStatus().isOk(); - } - - @TestConfiguration - static class WebClientConfig { - @Bean - WebClient web() { - return WebClient.create(web.url("/").toString()); - } - } -} diff --git a/samples/boot/oauth2webclient/README.adoc b/samples/boot/oauth2webclient/README.adoc deleted file mode 100644 index b234f34f7e..0000000000 --- a/samples/boot/oauth2webclient/README.adoc +++ /dev/null @@ -1,63 +0,0 @@ -= OAuth 2.0 WebClient (Servlet) Sample - -== GitHub Repositories - -This guide provides instructions on setting up the sample application, which leverages WebClient OAuth2 integration to display a list of public GitHub repositories that are accessible to the authenticated user. - -This includes repositories owned by the authenticated user, repositories where the authenticated user is a collaborator, and repositories that the authenticated user has access to through an organization membership. - -The following sections provide detailed steps for setting up the sample and covers the following topics: - -* <> -* <> -* <> - -[[github-register-application]] -=== Register OAuth application - -To use GitHub's OAuth 2.0 authorization system, you must https://github.com/settings/applications/new[Register a new OAuth application]. - -When registering the OAuth application, ensure the *Authorization callback URL* is set to `http://localhost:8080/login/oauth2/code/client-id`. - -The Authorization callback URL (redirect URI) is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with GitHub and have granted access to the OAuth application on the _Authorize application_ page. - -[[github-application-config]] -=== Configure application.yml - -Now that you have a new OAuth application with GitHub, you need to configure the sample to use the OAuth application for the _authorization code grant flow_. -To do so: - -. Go to `application.yml` and set the following configuration: -+ -[source,yaml] ----- -spring: - security: - oauth2: - client: - registration: <1> - client-id: <2> - client-id: replace-with-client-id - client-secret: replace-with-client-secret - provider: github - scope: read:user,public_repo ----- -+ -.OAuth Client properties -==== -<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the `ClientRegistration`, which is github. -==== - -. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. - -[[github-boot-application]] -=== Boot up the application - -Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. -You are then redirected to the default _auto-generated_ form login page. -Log in using *'user'* (username) and *'password'* (password) or click the link to authenticate with GitHub and then you'll be redirected to GitHub for authentication. - -After authenticating with your GitHub credentials, the next page presented to you is "Authorize application". -This page will ask you to *Authorize* the application you created in the previous step. -Click _Authorize application_ to allow the OAuth application to access and display your public repository information. diff --git a/samples/boot/oauth2webclient/spring-security-samples-boot-oauth2webclient.gradle b/samples/boot/oauth2webclient/spring-security-samples-boot-oauth2webclient.gradle deleted file mode 100644 index f65d82709c..0000000000 --- a/samples/boot/oauth2webclient/spring-security-samples-boot-oauth2webclient.gradle +++ /dev/null @@ -1,16 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-oauth2-client') - compile project(':spring-security-oauth2-jose') - compile 'org.springframework:spring-webflux' - compile 'org.springframework.boot:spring-boot-starter-thymeleaf' - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' - compile 'io.projectreactor.netty:reactor-netty' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' - testCompile 'com.squareup.okhttp3:mockwebserver' -} diff --git a/samples/boot/oauth2webclient/src/main/java/sample/OAuth2WebClientApplication.java b/samples/boot/oauth2webclient/src/main/java/sample/OAuth2WebClientApplication.java deleted file mode 100644 index 4c4a6b7de1..0000000000 --- a/samples/boot/oauth2webclient/src/main/java/sample/OAuth2WebClientApplication.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration; - -/** - * @author Joe Grandja - */ -// FIXME: Work around https://github.com/spring-projects/spring-boot/issues/14463 -@SpringBootApplication(exclude = ReactiveOAuth2ClientAutoConfiguration.class) -public class OAuth2WebClientApplication { - - public static void main(String[] args) { - SpringApplication.run(OAuth2WebClientApplication.class, args); - } -} diff --git a/samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java b/samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java deleted file mode 100644 index e5602d812d..0000000000 --- a/samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; - -import static org.springframework.security.config.Customizer.withDefaults; - -/** - * @author Joe Grandja - */ -@EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests((authorizeRequests) -> - authorizeRequests - .mvcMatchers("/", "/public/**").permitAll() - .anyRequest().authenticated() - ) - .formLogin(withDefaults()) - .oauth2Login(withDefaults()) - .oauth2Client(withDefaults()); - } - - @Bean - public UserDetailsService userDetailsService() { - UserDetails userDetails = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("USER") - .build(); - return new InMemoryUserDetailsManager(userDetails); - } -} diff --git a/samples/boot/oauth2webclient/src/main/java/sample/config/WebClientConfig.java b/samples/boot/oauth2webclient/src/main/java/sample/config/WebClientConfig.java deleted file mode 100644 index da9510602b..0000000000 --- a/samples/boot/oauth2webclient/src/main/java/sample/config/WebClientConfig.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.config; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; -import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction; -import org.springframework.web.reactive.function.client.WebClient; - -/** - * @author Rob Winch - * @since 5.1 - */ -@Configuration -public class WebClientConfig { - - @Value("${resource-uri}") String resourceUri; - - @Bean - WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) { - ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = - new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); - oauth2.setDefaultOAuth2AuthorizedClient(true); - return WebClient.builder() - .baseUrl(this.resourceUri) - .apply(oauth2.oauth2Configuration()) - .build(); - } - - @Bean - OAuth2AuthorizedClientManager authorizedClientManager(ClientRegistrationRepository clientRegistrationRepository, - OAuth2AuthorizedClientRepository authorizedClientRepository) { - OAuth2AuthorizedClientProvider authorizedClientProvider = - OAuth2AuthorizedClientProviderBuilder.builder() - .authorizationCode() - .refreshToken() - .clientCredentials() - .password() - .build(); - DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager( - clientRegistrationRepository, authorizedClientRepository); - authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); - - return authorizedClientManager; - } -} diff --git a/samples/boot/oauth2webclient/src/main/java/sample/web/IndexController.java b/samples/boot/oauth2webclient/src/main/java/sample/web/IndexController.java deleted file mode 100644 index e1e0035ef1..0000000000 --- a/samples/boot/oauth2webclient/src/main/java/sample/web/IndexController.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.web; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; - -/** - * @author Rob Winch - */ -@Controller -public class IndexController { - @GetMapping("/") - String index() { - return "index"; - } -} diff --git a/samples/boot/oauth2webclient/src/main/java/sample/web/OAuth2WebClientController.java b/samples/boot/oauth2webclient/src/main/java/sample/web/OAuth2WebClientController.java deleted file mode 100644 index f20b479d1f..0000000000 --- a/samples/boot/oauth2webclient/src/main/java/sample/web/OAuth2WebClientController.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.web; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId; - -/** - * @author Joe Grandja - * @author Rob Winch - */ -@Controller -@RequestMapping(path = {"/webclient", "/public/webclient"}) -public class OAuth2WebClientController { - private final WebClient webClient; - - public OAuth2WebClientController(WebClient webClient) { - this.webClient = webClient; - } - - @GetMapping("/explicit") - String explicit(Model model) { - String body = this.webClient - .get() - .attributes(clientRegistrationId("client-id")) - .retrieve() - .bodyToMono(String.class) - .block(); - model.addAttribute("body", body); - return "response"; - } - - @GetMapping("/implicit") - String implicit(Model model) { - String body = this.webClient - .get() - .retrieve() - .bodyToMono(String.class) - .block(); - model.addAttribute("body", body); - return "response"; - } -} diff --git a/samples/boot/oauth2webclient/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java b/samples/boot/oauth2webclient/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java deleted file mode 100644 index 883db445d0..0000000000 --- a/samples/boot/oauth2webclient/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.web; - -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient; - -/** - * @author Joe Grandja - * @author Rob Winch - */ -@Controller -@RequestMapping(path = {"/annotation", "/public/annotation"}) -public class RegisteredOAuth2AuthorizedClientController { - private final WebClient webClient; - - public RegisteredOAuth2AuthorizedClientController(WebClient webClient) { - this.webClient = webClient; - } - - @GetMapping("/explicit") - String explicit(Model model, @RegisteredOAuth2AuthorizedClient("client-id") OAuth2AuthorizedClient authorizedClient) { - String body = this.webClient - .get() - .attributes(oauth2AuthorizedClient(authorizedClient)) - .retrieve() - .bodyToMono(String.class) - .block(); - model.addAttribute("body", body); - return "response"; - } - - @GetMapping("/implicit") - String implicit(Model model, @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient) { - String body = this.webClient - .get() - .attributes(oauth2AuthorizedClient(authorizedClient)) - .retrieve() - .bodyToMono(String.class) - .block(); - model.addAttribute("body", body); - return "response"; - } -} diff --git a/samples/boot/oauth2webclient/src/main/resources/application.yml b/samples/boot/oauth2webclient/src/main/resources/application.yml deleted file mode 100644 index 8528a06d0d..0000000000 --- a/samples/boot/oauth2webclient/src/main/resources/application.yml +++ /dev/null @@ -1,21 +0,0 @@ -logging: - level: - root: INFO - org.springframework.web: INFO - org.springframework.security: INFO -# org.springframework.boot.autoconfigure: DEBUG - -spring: - thymeleaf: - cache: false - security: - oauth2: - client: - registration: - client-id: - client-id: replace-with-client-id - client-secret: replace-with-client-secret - provider: github - scope: read:user,public_repo - -resource-uri: https://api.github.com/user/repos diff --git a/samples/boot/oauth2webclient/src/main/resources/templates/index.html b/samples/boot/oauth2webclient/src/main/resources/templates/index.html deleted file mode 100644 index 07a8e68035..0000000000 --- a/samples/boot/oauth2webclient/src/main/resources/templates/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - OAuth2 WebClient Showcase - - - -Log Out -

Examples

- -

@RegisteredOAuth2AuthorizedClient

-

-Examples on RegisteredOAuth2AuthorizedClientController -

Authenticated

-
    -
  • Explicit - Explicitly provide a Client Registration Id
  • -
  • - Implicit - Use the currently logged in user's OAuth Token. This will - only work if the user authenticates with oauth2Login and the token provided is the correct token provided at - log in is authorized.
  • -
-

Public

-
    -
  • Explicit - Explicitly provide a Client Registration Id
  • -
  • - Implicit - This will fail if the user is not authenticated. - Since it is mapped to permitAll, it is going to fail unless the user already took an action to log in and then - authenticates with oauth2Login()
  • -
- -

ServletOAuth2AuthorizedClientExchangeFilterFunction

-

- Examples on OAuth2WebClientController that demonstrate how to use ServletOAuth2AuthorizedClientExchangeFilterFunction -

Authenticated

-
    -
  • Explicit - Explicitly provide a Client Registration Id
  • -
  • - Implicit - Use the currently logged in user's OAuth Token. This will - only work if the user authenticates with oauth2Login and the token provided is the correct token provided at - log in is authorized.
  • -
-

Public

-
    -
  • Explicit - Explicitly provide a Client Registration Id
  • -
  • - Implicit - This will fail if the user is not authenticated. - Since it is mapped to permitAll, it is going to fail unless the user already took an action to log in and then - authenticates with oauth2Login()
  • -
- - diff --git a/samples/boot/oauth2webclient/src/main/resources/templates/response.html b/samples/boot/oauth2webclient/src/main/resources/templates/response.html deleted file mode 100644 index 210c18c29a..0000000000 --- a/samples/boot/oauth2webclient/src/main/resources/templates/response.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - OAuth2 WebClient Showcase - - - -Back -

Response

-
- - - diff --git a/samples/boot/oauth2webclient/src/test/java/sample/OAuth2WebClientApplicationTests.java b/samples/boot/oauth2webclient/src/test/java/sample/OAuth2WebClientApplicationTests.java deleted file mode 100644 index 4e153b9961..0000000000 --- a/samples/boot/oauth2webclient/src/test/java/sample/OAuth2WebClientApplicationTests.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * @author Rob Winch - */ -@SpringBootTest -@AutoConfigureMockMvc -@RunWith(SpringRunner.class) -public class OAuth2WebClientApplicationTests { - @Autowired - private MockMvc mockMvc; - - @Test - public void annotationExplicitWhenNotAuthenticatedThenLoginRequested() throws Exception { - this.mockMvc.perform(get("/annotation/explicit")) - .andExpect(status().is3xxRedirection()); - } -} diff --git a/samples/boot/oauth2webclient/src/test/java/sample/OAuth2WebClientControllerTests.java b/samples/boot/oauth2webclient/src/test/java/sample/OAuth2WebClientControllerTests.java deleted file mode 100644 index 8829c00471..0000000000 --- a/samples/boot/oauth2webclient/src/test/java/sample/OAuth2WebClientControllerTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.junit.AfterClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Client; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@WebMvcTest -@AutoConfigureMockMvc -@RunWith(SpringRunner.class) -public class OAuth2WebClientControllerTests { - private static MockWebServer web = new MockWebServer(); - - @Autowired - private MockMvc mockMvc; - - @AfterClass - public static void shutdown() throws Exception { - web.shutdown(); - } - - @Test - public void explicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.mockMvc.perform(get("/webclient/explicit") - .with(oauth2Login()) - .with(oauth2Client("client-id"))) - .andExpect(status().isOk()); - } - - @Test - public void implicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.mockMvc.perform(get("/webclient/implicit") - .with(oauth2Login())) - .andExpect(status().isOk()); - } - - @Test - public void publicExplicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.mockMvc.perform(get("/public/webclient/explicit") - .with(oauth2Client("client-id"))) - .andExpect(status().isOk()); - } - - @Test - public void publicImplicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.mockMvc.perform(get("/public/webclient/implicit") - .with(oauth2Login())) - .andExpect(status().isOk()); - } - - @TestConfiguration - static class WebClientConfig { - @Bean - WebClient web() { - return WebClient.create(web.url("/").toString()); - } - } -} diff --git a/samples/boot/oauth2webclient/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java b/samples/boot/oauth2webclient/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java deleted file mode 100644 index 91e3a2ec91..0000000000 --- a/samples/boot/oauth2webclient/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.junit.AfterClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Client; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@WebMvcTest -@AutoConfigureMockMvc -@RunWith(SpringRunner.class) -public class RegisteredOAuth2AuthorizedClientControllerTests { - private static MockWebServer web = new MockWebServer(); - - @Autowired - private MockMvc mockMvc; - - @AfterClass - public static void shutdown() throws Exception { - web.shutdown(); - } - - @Test - public void annotationExplicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.mockMvc.perform(get("/annotation/explicit") - .with(oauth2Login()) - .with(oauth2Client("client-id"))) - .andExpect(status().isOk()); - } - - @Test - public void annotationImplicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.mockMvc.perform(get("/annotation/implicit") - .with(oauth2Login())) - .andExpect(status().isOk()); - } - - @Test - public void publicAnnotationExplicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.mockMvc.perform(get("/public/annotation/explicit") - .with(oauth2Client("client-id"))) - .andExpect(status().isOk()); - } - - @Test - public void publicAnnotationImplicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { - web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); - this.mockMvc.perform(get("/public/annotation/implicit") - .with(oauth2Login())) - .andExpect(status().isOk()); - } - - @TestConfiguration - static class WebClientConfig { - @Bean - WebClient web() { - return WebClient.create(web.url("/").toString()); - } - } -} diff --git a/samples/boot/saml2login/README.adoc b/samples/boot/saml2login/README.adoc deleted file mode 100644 index d51b1bba4b..0000000000 --- a/samples/boot/saml2login/README.adoc +++ /dev/null @@ -1,38 +0,0 @@ -= SAML 2.0 Login Sample - -This guide provides instructions on setting up this SAML 2.0 Login sample application. - -The sample application uses Spring Boot and the `spring-security-saml2-service-provider` -module which is new in Spring Security 5.2. - -== Goals - -`saml2Login()` provides a very simple implementation of a Service Provider that can receive a SAML 2.0 Response via the HTTP-POST and HTTP-REDIRECT bindings against the SimpleSAMLphp SAML 2.0 reference implementation. - -The following features are implemented in the MVP: - -1. Receive and validate a SAML 2.0 Response containing an assertion, and create a corresponding authentication in Spring Security -2. Send a SAML 2.0 AuthNRequest to an Identity Provider -3. Provide a framework for components used in SAML 2.0 authentication that can be swapped by configuration -4. Work against the SimpleSAMLphp reference implementation - -== Run the Sample - -=== Start up the Sample Boot Application -``` - ./gradlew :spring-security-samples-boot-saml2login:bootRun -``` - -=== Open a Browser - -http://localhost:8080/ - -You will be redirect to the SimpleSAMLphp IDP - -=== Type in your credentials - -``` -User: user -Password: password -``` - diff --git a/samples/boot/saml2login/spring-security-samples-boot-saml2login.gradle b/samples/boot/saml2login/spring-security-samples-boot-saml2login.gradle deleted file mode 100644 index ee78e3f199..0000000000 --- a/samples/boot/saml2login/spring-security-samples-boot-saml2login.gradle +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'io.spring.convention.spring-sample-boot' - -sourceCompatibility = '11' - -repositories { - maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" } -} - -dependencies { - compile project(':spring-security-config') - compile project(':saml2-service-provider-opensaml4') - compile 'org.springframework.boot:spring-boot-starter-thymeleaf' - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' - - testCompile project(':spring-security-test') - testCompile 'net.sourceforge.htmlunit:htmlunit' - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/saml2login/src/integration-test/java/sample/Saml2LoginApplicationITests.java b/samples/boot/saml2login/src/integration-test/java/sample/Saml2LoginApplicationITests.java deleted file mode 100644 index c963ab3b2b..0000000000 --- a/samples/boot/saml2login/src/integration-test/java/sample/Saml2LoginApplicationITests.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import javax.servlet.http.HttpSession; - -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlForm; -import com.gargoylesoftware.htmlunit.html.HtmlInput; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.mock.web.MockHttpSession; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -public class Saml2LoginApplicationITests { - static final String SIGNED_RESPONSE = "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElEPSJfY2UyYjU4NTVjZjU5YmEyNDc4OTUyOGRkOGQzZDcyOGRiMGViZjNlNzNiIiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAyMS0wMS0yMFQwMTowMzoyNFoiIERlc3RpbmF0aW9uPSJodHRwOi8vbG9jYWxob3N0OjgwODAvbG9naW4vc2FtbDIvc3NvL29uZSIgSW5SZXNwb25zZVRvPSJBUlFjOThmMjAwLWRjZjctNGRmNC1hNTIyLTA3MjA2MjA4YjA3ZCI+PHNhbWw6SXNzdWVyPmh0dHBzOi8vc2ltcGxlc2FtbC1mb3Itc3ByaW5nLXNhbWwuYXBwcy5wY2ZvbmUuaW8vc2FtbDIvaWRwL21ldGFkYXRhLnBocDwvc2FtbDpJc3N1ZXI+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+CiAgPGRzOlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz4KICAgIDxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8+CiAgPGRzOlJlZmVyZW5jZSBVUkk9IiNfY2UyYjU4NTVjZjU5YmEyNDc4OTUyOGRkOGQzZDcyOGRiMGViZjNlNzNiIj48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiLz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+TXJUNS8wdTRScTl3QmMvejFQd2FrNURXZm1xOGlOVk52NldHZWFnZUVzUT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+WWg1UFE5cFVBbkkvOW5tNzgxZ040bThTS0U4T1VRTDVOMlI3ZklPZmtHVmMzRjhzNlJlR3hRNWFneUFXYnQzUDRwQ3RWeGtqbk4rMk5KeUw4QmhRMHN0dEovb2JFTHJGUldLemYyYUJaS2NCN0JHTFNtRXdoUFE3N3BHL0psMjBhaDQyaGRyWFc3TE9Ob0VZOHMyY093dm16NkQ2bW9YQWprMHV2UEVTNjhUVndxU2VmT3JwNXV0QmRSQUt6cUJRQ2NQWFJCdnB5NWJ3QkpDL2RKNE5QLzJpalE3N2I3eWhvVDQ0R21hSUduSGo0YVFaeG9kY1JuNU9oQ2hYRk4ydUk2YW1mT0ZYOThjUXZ5KzhDWm9YYUZRMnJmT2dPbGdzbmNGWGMwaXhYK05MSjlvSlJWT2hxRVpjY2JoZ3hPM2hpQ2UwemRuZHloVWxpaGMwdFU2OVlBPT08L2RzOlNpZ25hdHVyZVZhbHVlPgo8ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlFRXpDQ0F2dWdBd0lCQWdJSkFJYzFxekxydis1bk1BMEdDU3FHU0liM0RRRUJDd1VBTUlHZk1Rc3dDUVlEVlFRR0V3SlZVekVMTUFrR0ExVUVDQXdDUTA4eEZEQVNCZ05WQkFjTUMwTmhjM1JzWlNCU2IyTnJNUnd3R2dZRFZRUUtEQk5UWVcxc0lGUmxjM1JwYm1jZ1UyVnlkbVZ5TVFzd0NRWURWUVFMREFKSlZERWdNQjRHQTFVRUF3d1hjMmx0Y0d4bGMyRnRiSEJvY0M1alptRndjSE11YVc4eElEQWVCZ2txaGtpRzl3MEJDUUVXRVdab1lXNXBhMEJ3YVhadmRHRnNMbWx2TUI0WERURTFNREl5TXpJeU5EVXdNMW9YRFRJMU1ESXlNakl5TkRVd00xb3dnWjh4Q3pBSkJnTlZCQVlUQWxWVE1Rc3dDUVlEVlFRSURBSkRUekVVTUJJR0ExVUVCd3dMUTJGemRHeGxJRkp2WTJzeEhEQWFCZ05WQkFvTUUxTmhiV3dnVkdWemRHbHVaeUJUWlhKMlpYSXhDekFKQmdOVkJBc01Ba2xVTVNBd0hnWURWUVFEREJkemFXMXdiR1Z6WVcxc2NHaHdMbU5tWVhCd2N5NXBiekVnTUI0R0NTcUdTSWIzRFFFSkFSWVJabWhoYm1sclFIQnBkbTkwWVd3dWFXOHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDNGNuNjJFMXhMcXBOMzRQbWJyS0Jia09YRmp6V2dKOWIrcFh1YVJmdDZBMzM5dXVJUWVvZUg1cWVTS1JWVGwzMkwwZ2R6Mlppdkx3WlhXK2NxdmZ0VlcxdHZFSHZ6SkZ5eGVUVzNmQ1VlQ1FzZWJMbkEycVJhMDdSa3hUbzZOZjI0NG1XV1JEb2Rjb0hFZkRVU2J4ZlRaNklFeFNvalNJVTJSbkQ2V2xsWVdGZEQxR0ZwQkpPbVFCOHJBYzh3SklCZEhGZFFuWDhUdGw3aFo2cnRncUVZTXpZVk11SjJGMnIxSFNVMXpTQXZ3cGRZUDZyUkdGUkpFZmRBOW1tM1dLZk5MU2M1Y2xqejBYL1RYeTB2VmxBVjk1bDlxY2ZGelBtcmtOSXN0OUZaU3dwdkI0OUx5QVZrZTA0RlFQUHdMZ1ZINGdwaGlKSDNqdlo3SStKNWxTOFZBZ01CQUFHalVEQk9NQjBHQTFVZERnUVdCQlRUeVA2Q2M1SGxCSjUrdWNWQ3dHYzVvZ0tOR3pBZkJnTlZIU01FR0RBV2dCVFR5UDZDYzVIbEJKNSt1Y1ZDd0djNW9nS05HekFNQmdOVkhSTUVCVEFEQVFIL01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQXZNUzRFUWVQL2lwVjRqT0c1bE82L3RZQ2IvaUplQWR1T25SaGtKazBEYlgzMjlsRExaaFRUTC94L3cvOW11Q1ZjdkxyekVwNlBOK1ZXZnc1RTVGV3RaTjB5aEd0UDlSK3ZabnJWK29jMnpHRCtubzEveVNGT2UzRWlKQ081ZGVoeEtqWUVtQlJ2NXNVL0xaRktacG96S04vQk1FYTZDcUx1eGJ6Yjd5a3hWcjdFVkZYd2x0UHh6RTlUbUw5T0FDTk55RjVlSkhXTVJNbGxhclV2a2NYbGg0cHV4NGtzOWU2elY5RFFCeTJ6ZHM5ZjFJM3F4ZzBlWDZKbkdyWGkvWmlDVCtsSmdWZTNaRlhpZWppTEFpS0IwNHNYVzN0aTBMVzNseDEzWTFZbFE0L3RscGdUZ2ZJSnhLVjZueVBpTG9LMG55d2JNZCt2cEFpckR0Mk9jK2hrPC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWxwOlN0YXR1cz48c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+PC9zYW1scDpTdGF0dXM+PHNhbWw6QXNzZXJ0aW9uIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgSUQ9Il9jYjYzYmMzNmMyYzAzYjRlMWJjZDViMWIwY2MyZTE2NWQwNDQ1NDZlODgiIFZlcnNpb249IjIuMCIgSXNzdWVJbnN0YW50PSIyMDIxLTAxLTIwVDAxOjAzOjI0WiI+PHNhbWw6SXNzdWVyPmh0dHBzOi8vc2ltcGxlc2FtbC1mb3Itc3ByaW5nLXNhbWwuYXBwcy5wY2ZvbmUuaW8vc2FtbDIvaWRwL21ldGFkYXRhLnBocDwvc2FtbDpJc3N1ZXI+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+CiAgPGRzOlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz4KICAgIDxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8+CiAgPGRzOlJlZmVyZW5jZSBVUkk9IiNfY2I2M2JjMzZjMmMwM2I0ZTFiY2Q1YjFiMGNjMmUxNjVkMDQ0NTQ2ZTg4Ij48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiLz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+VWFtN2NHVGlCd2xuRDBJdGd5aU5KVjN2Z0NPNytZZkRxSWJrWERkR3hrQT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+RkhpWUpETDlKTXM1Y2V5WXhUVVgrUndEQm45RFYzVE81dDFham4raGFtb1c2MUpBY0JaNjEwUHpYMzN3alA3Mk1kYmdDWnR5ZmNrSktZUUpPT0szRkxLTkJLQkphOTNsSS9rZWZjTXRTUGxBU2hESm9ydmU0U0tWa29WbzZLVnB0eC9OTnowRkhJNURFZTZiUUVjZWFiNERVNDFVdEpQMHUyWm16ejVjNC83VzhLdmt6MkxMbXhWZlE3Q2todmgvNzBhWHlkWVBVRml3bE4vV1lTV3JYVU9oOXNFTDFiZGVlQzFkYnpaeVdNNldnSkdRMUpJblBnSGd0YTlxMU96eGliOFlLRXpQSUMzVEZldkU1Y0phMFQvd1NzOVIxN0JSR09OclhTTWQvRCt4YkY0Z3lIYW5EZFlOYVN2TzdIS2p4bzRwYk1aY05peDhMTkVYZGtiZEx3PT08L2RzOlNpZ25hdHVyZVZhbHVlPgo8ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlFRXpDQ0F2dWdBd0lCQWdJSkFJYzFxekxydis1bk1BMEdDU3FHU0liM0RRRUJDd1VBTUlHZk1Rc3dDUVlEVlFRR0V3SlZVekVMTUFrR0ExVUVDQXdDUTA4eEZEQVNCZ05WQkFjTUMwTmhjM1JzWlNCU2IyTnJNUnd3R2dZRFZRUUtEQk5UWVcxc0lGUmxjM1JwYm1jZ1UyVnlkbVZ5TVFzd0NRWURWUVFMREFKSlZERWdNQjRHQTFVRUF3d1hjMmx0Y0d4bGMyRnRiSEJvY0M1alptRndjSE11YVc4eElEQWVCZ2txaGtpRzl3MEJDUUVXRVdab1lXNXBhMEJ3YVhadmRHRnNMbWx2TUI0WERURTFNREl5TXpJeU5EVXdNMW9YRFRJMU1ESXlNakl5TkRVd00xb3dnWjh4Q3pBSkJnTlZCQVlUQWxWVE1Rc3dDUVlEVlFRSURBSkRUekVVTUJJR0ExVUVCd3dMUTJGemRHeGxJRkp2WTJzeEhEQWFCZ05WQkFvTUUxTmhiV3dnVkdWemRHbHVaeUJUWlhKMlpYSXhDekFKQmdOVkJBc01Ba2xVTVNBd0hnWURWUVFEREJkemFXMXdiR1Z6WVcxc2NHaHdMbU5tWVhCd2N5NXBiekVnTUI0R0NTcUdTSWIzRFFFSkFSWVJabWhoYm1sclFIQnBkbTkwWVd3dWFXOHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDNGNuNjJFMXhMcXBOMzRQbWJyS0Jia09YRmp6V2dKOWIrcFh1YVJmdDZBMzM5dXVJUWVvZUg1cWVTS1JWVGwzMkwwZ2R6Mlppdkx3WlhXK2NxdmZ0VlcxdHZFSHZ6SkZ5eGVUVzNmQ1VlQ1FzZWJMbkEycVJhMDdSa3hUbzZOZjI0NG1XV1JEb2Rjb0hFZkRVU2J4ZlRaNklFeFNvalNJVTJSbkQ2V2xsWVdGZEQxR0ZwQkpPbVFCOHJBYzh3SklCZEhGZFFuWDhUdGw3aFo2cnRncUVZTXpZVk11SjJGMnIxSFNVMXpTQXZ3cGRZUDZyUkdGUkpFZmRBOW1tM1dLZk5MU2M1Y2xqejBYL1RYeTB2VmxBVjk1bDlxY2ZGelBtcmtOSXN0OUZaU3dwdkI0OUx5QVZrZTA0RlFQUHdMZ1ZINGdwaGlKSDNqdlo3SStKNWxTOFZBZ01CQUFHalVEQk9NQjBHQTFVZERnUVdCQlRUeVA2Q2M1SGxCSjUrdWNWQ3dHYzVvZ0tOR3pBZkJnTlZIU01FR0RBV2dCVFR5UDZDYzVIbEJKNSt1Y1ZDd0djNW9nS05HekFNQmdOVkhSTUVCVEFEQVFIL01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQXZNUzRFUWVQL2lwVjRqT0c1bE82L3RZQ2IvaUplQWR1T25SaGtKazBEYlgzMjlsRExaaFRUTC94L3cvOW11Q1ZjdkxyekVwNlBOK1ZXZnc1RTVGV3RaTjB5aEd0UDlSK3ZabnJWK29jMnpHRCtubzEveVNGT2UzRWlKQ081ZGVoeEtqWUVtQlJ2NXNVL0xaRktacG96S04vQk1FYTZDcUx1eGJ6Yjd5a3hWcjdFVkZYd2x0UHh6RTlUbUw5T0FDTk55RjVlSkhXTVJNbGxhclV2a2NYbGg0cHV4NGtzOWU2elY5RFFCeTJ6ZHM5ZjFJM3F4ZzBlWDZKbkdyWGkvWmlDVCtsSmdWZTNaRlhpZWppTEFpS0IwNHNYVzN0aTBMVzNseDEzWTFZbFE0L3RscGdUZ2ZJSnhLVjZueVBpTG9LMG55d2JNZCt2cEFpckR0Mk9jK2hrPC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWw6U3ViamVjdD48c2FtbDpOYW1lSUQgU1BOYW1lUXVhbGlmaWVyPSJodHRwOi8vbG9jYWxob3N0OjgwODAvc2FtbDIvc2VydmljZS1wcm92aWRlci1tZXRhZGF0YS9vbmUiIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6ZW1haWxBZGRyZXNzIj50ZXN0dXNlckBzcHJpbmcuc2VjdXJpdHkuc2FtbDwvc2FtbDpOYW1lSUQ+PHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbiBNZXRob2Q9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjbTpiZWFyZXIiPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb25EYXRhIE5vdE9uT3JBZnRlcj0iMjA1Mi0wOS0yOFQwMjo1MDowNFoiIFJlY2lwaWVudD0iaHR0cDovL2xvY2FsaG9zdDo4MDgwL2xvZ2luL3NhbWwyL3Nzby9vbmUiIEluUmVzcG9uc2VUbz0iQVJRYzk4ZjIwMC1kY2Y3LTRkZjQtYTUyMi0wNzIwNjIwOGIwN2QiLz48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAyMS0wMS0yMFQwMTowMjo1NFoiIE5vdE9uT3JBZnRlcj0iMjA1Mi0wOS0yOFQwMjo1MDowNFoiPjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb24+PHNhbWw6QXVkaWVuY2U+aHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbWwyL3NlcnZpY2UtcHJvdmlkZXItbWV0YWRhdGEvb25lPC9zYW1sOkF1ZGllbmNlPjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uPjwvc2FtbDpDb25kaXRpb25zPjxzYW1sOkF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAyMS0wMS0yMFQwMDo0ODoyOVoiIFNlc3Npb25Ob3RPbk9yQWZ0ZXI9IjIwMjEtMDEtMjBUMDg6NDg6MjlaIiBTZXNzaW9uSW5kZXg9Il9lN2ExYTllNDk1YmZlMjI2NjQ5ZThkY2MzN2UxNDE1NDQ5NTIxNWQ2ZWIiPjxzYW1sOkF1dGhuQ29udGV4dD48c2FtbDpBdXRobkNvbnRleHRDbGFzc1JlZj51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydDwvc2FtbDpBdXRobkNvbnRleHRDbGFzc1JlZj48L3NhbWw6QXV0aG5Db250ZXh0Pjwvc2FtbDpBdXRoblN0YXRlbWVudD48c2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+PHNhbWw6QXR0cmlidXRlIE5hbWU9InVpZCIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzOnN0cmluZyI+dGVzdHVzZXJAc3ByaW5nLnNlY3VyaXR5LnNhbWw8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgTmFtZT0iZWR1UGVyc29uQWZmaWxpYXRpb24iIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6YmFzaWMiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlIHhzaTp0eXBlPSJ4czpzdHJpbmciPm1lbWJlcjwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48c2FtbDpBdHRyaWJ1dGVWYWx1ZSB4c2k6dHlwZT0ieHM6c3RyaW5nIj51c2VyPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIE5hbWU9ImVtYWlsQWRkcmVzcyIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzOnN0cmluZyI+dGVzdHVzZXJAc3ByaW5nLnNlY3VyaXR5LnNhbWw8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48L3NhbWw6QXR0cmlidXRlU3RhdGVtZW50Pjwvc2FtbDpBc3NlcnRpb24+PC9zYW1scDpSZXNwb25zZT4="; - - static final Map> USER_ATTRIBUTES = new LinkedHashMap<>(); - - static { - USER_ATTRIBUTES.put("uid", Arrays.asList("testuser@spring.security.saml")); - USER_ATTRIBUTES.put("eduPersonAffiliation", Arrays.asList("member", "user")); - USER_ATTRIBUTES.put("emailAddress", Arrays.asList("testuser@spring.security.saml")); - } - - @Autowired - MockMvc mvc; - - @Autowired - WebClient webClient; - - @Test - public void indexWhenSamlResponseThenShowsUserInformation() throws Exception { - HttpSession session = this.mvc.perform(get("http://localhost:8080/")) - .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("http://localhost:8080/saml2/authenticate/one")) - .andReturn() - .getRequest().getSession(); - - this.mvc.perform(post("http://localhost:8080/login/saml2/sso/one") - .param("SAMLResponse", SIGNED_RESPONSE) - .session((MockHttpSession) session)) - .andExpect(redirectedUrl("http://localhost:8080/")); - - this.mvc.perform(get("http://localhost:8080/") - .session((MockHttpSession) session)) - .andExpect(model().attribute("emailAddress", "testuser@spring.security.saml")) - .andExpect(model().attribute("userAttributes", USER_ATTRIBUTES)); - } - - @Test - public void authenticationAttemptWhenValidThenShowsUserEmailAddress() throws Exception { - HtmlPage assertingParty = this.webClient.getPage("/"); - HtmlForm form = assertingParty.getFormByName("f"); - HtmlInput username = form.getInputByName("username"); - HtmlInput password = form.getInputByName("password"); - HtmlSubmitInput submit = assertingParty.getHtmlElementById("submit_button"); - username.setValueAttribute("user"); - password.setValueAttribute("password"); - HtmlPage relyingParty = submit.click(); - assertThat(relyingParty.asText()) - .contains("You're email address is testuser@spring.security.saml"); - } -} diff --git a/samples/boot/saml2login/src/main/java/sample/IndexController.java b/samples/boot/saml2login/src/main/java/sample/IndexController.java deleted file mode 100644 index 8da3c251eb..0000000000 --- a/samples/boot/saml2login/src/main/java/sample/IndexController.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; - -@Controller -public class IndexController { - - @GetMapping("/") - public String index(Model model, - @AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) { - String emailAddress = principal.getFirstAttribute("emailAddress"); - model.addAttribute("emailAddress", emailAddress); - model.addAttribute("userAttributes", principal.getAttributes()); - return "index"; - } -} diff --git a/samples/boot/saml2login/src/main/java/sample/Saml2LoginApplication.java b/samples/boot/saml2login/src/main/java/sample/Saml2LoginApplication.java deleted file mode 100644 index 08202d28de..0000000000 --- a/samples/boot/saml2login/src/main/java/sample/Saml2LoginApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Saml2LoginApplication { - - public static void main(String[] args) { - SpringApplication.run(Saml2LoginApplication.class, args); - } - -} diff --git a/samples/boot/saml2login/src/main/java/sample/SecurityConfig.java b/samples/boot/saml2login/src/main/java/sample/SecurityConfig.java deleted file mode 100644 index 434cf36668..0000000000 --- a/samples/boot/saml2login/src/main/java/sample/SecurityConfig.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations; - -@Configuration -public class SecurityConfig { - @Bean - RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() { - RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations - .fromMetadataLocation("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php") - .registrationId("one") - .build(); - return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration); - } -} diff --git a/samples/boot/saml2login/src/main/resources/application.yml b/samples/boot/saml2login/src/main/resources/application.yml deleted file mode 100644 index 8b13789179..0000000000 --- a/samples/boot/saml2login/src/main/resources/application.yml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/samples/boot/saml2login/src/main/resources/templates/index.html b/samples/boot/saml2login/src/main/resources/templates/index.html deleted file mode 100644 index b72bb58ce0..0000000000 --- a/samples/boot/saml2login/src/main/resources/templates/index.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - Spring Security - SAML 2.0 Login - - - - - -

SAML 2.0 Login with Spring Security

-

You are successfully logged in as

-

You're email address is

-

All Your Attributes

-
-
-
-
- - diff --git a/samples/boot/webflux-form/spring-security-samples-boot-webflux-form.gradle b/samples/boot/webflux-form/spring-security-samples-boot-webflux-form.gradle deleted file mode 100644 index 35d9a28149..0000000000 --- a/samples/boot/webflux-form/spring-security-samples-boot-webflux-form.gradle +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-core') - compile project(':spring-security-config') - compile project(':spring-security-web') - compile 'org.springframework.boot:spring-boot-starter-thymeleaf' - compile 'org.springframework.boot:spring-boot-starter-webflux' - compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' - - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' - testCompile 'io.projectreactor:reactor-test' - testCompile 'org.skyscreamer:jsonassert' - testCompile 'org.springframework:spring-test' - - integrationTestCompile seleniumDependencies -} - diff --git a/samples/boot/webflux-form/src/integration-test/java/sample/WebfluxFormApplicationTests.java b/samples/boot/webflux-form/src/integration-test/java/sample/WebfluxFormApplicationTests.java deleted file mode 100644 index c9062faa59..0000000000 --- a/samples/boot/webflux-form/src/integration-test/java/sample/WebfluxFormApplicationTests.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit4.SpringRunner; - -import com.gargoylesoftware.htmlunit.BrowserVersion; - -import sample.webdriver.IndexPage; -import sample.webdriver.LoginPage; - -/** - * @author Rob Winch - * @since 5.0 - */ -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class WebfluxFormApplicationTests { - WebDriver driver; - - @LocalServerPort - int port; - - @Before - public void setup() { - this.driver = new HtmlUnitDriver(BrowserVersion.CHROME); - } - - @Test - public void loginWhenInvalidUsernameThenError() { - LoginPage login = IndexPage.to(this.driver, this.port, LoginPage.class); - login.assertAt(); - - login - .loginForm() - .username("invalid") - .password("password") - .submit(LoginPage.class) - .assertError(); - } - - @Test - public void loginAndLogout() { - LoginPage login = IndexPage.to(this.driver, this.port, LoginPage.class); - login.assertAt(); - - IndexPage index = login - .loginForm() - .username("user") - .password("password") - .submit(IndexPage.class); - index.assertAt(); - - login = index.logout(); - login - .assertAt() - .assertLogout(); - } -} diff --git a/samples/boot/webflux-form/src/integration-test/java/sample/webdriver/IndexPage.java b/samples/boot/webflux-form/src/integration-test/java/sample/webdriver/IndexPage.java deleted file mode 100644 index 9ca07b68f7..0000000000 --- a/samples/boot/webflux-form/src/integration-test/java/sample/webdriver/IndexPage.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.webdriver; - -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.PageFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Rob Winch - * @since 5.0 - */ -public class IndexPage { - - private WebDriver driver; - - private WebElement logout; - - public IndexPage(WebDriver webDriver) { - this.driver = webDriver; - } - - public static T to(WebDriver driver, int port, Class page) { - driver.get("http://localhost:" + port +"/"); - return PageFactory.initElements(driver, page); - } - - public IndexPage assertAt() { - assertThat(this.driver.getTitle()).isEqualTo("Secured"); - return this; - } - - public LoginPage logout() { - this.logout.click(); - return LoginPage.create(this.driver); - } -} diff --git a/samples/boot/webflux-form/src/integration-test/java/sample/webdriver/LoginPage.java b/samples/boot/webflux-form/src/integration-test/java/sample/webdriver/LoginPage.java deleted file mode 100644 index 1058533866..0000000000 --- a/samples/boot/webflux-form/src/integration-test/java/sample/webdriver/LoginPage.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.webdriver; - -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Rob Winch - * @since 5.0 - */ -public class LoginPage { - - private WebDriver driver; - @FindBy(css = "div[role=alert]") - private WebElement alert; - - private LoginForm loginForm; - - public LoginPage(WebDriver webDriver) { - this.driver = webDriver; - this.loginForm = PageFactory.initElements(webDriver, LoginForm.class); - } - - static LoginPage create(WebDriver driver) { - return PageFactory.initElements(driver, LoginPage.class); - } - - public LoginPage assertAt() { - assertThat(this.driver.getTitle()).isEqualTo("Please Log In"); - return this; - } - - public LoginPage assertError() { - assertThat(this.alert.getText()).isEqualTo("Invalid username and password."); - return this; - } - - public LoginPage assertLogout() { - assertThat(this.alert.getText()).isEqualTo("You have been logged out."); - return this; - } - - public LoginForm loginForm() { - return this.loginForm; - } - - public static class LoginForm { - private WebDriver driver; - private WebElement username; - private WebElement password; - @FindBy(css = "button[type=submit]") - private WebElement submit; - - public LoginForm(WebDriver driver) { - this.driver = driver; - } - - public LoginForm username(String username) { - this.username.sendKeys(username); - return this; - } - - public LoginForm password(String password) { - this.password.sendKeys(password); - return this; - } - - public T submit(Class page) { - this.submit.click(); - return PageFactory.initElements(this.driver, page); - } - } -} diff --git a/samples/boot/webflux-form/src/main/java/sample/IndexController.java b/samples/boot/webflux-form/src/main/java/sample/IndexController.java deleted file mode 100644 index d84301d78b..0000000000 --- a/samples/boot/webflux-form/src/main/java/sample/IndexController.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; - -/** - * @author Rob Winch - * @since 5.0 - */ -@Controller -public class IndexController { - - @GetMapping("/") - public String index() { - return "index"; - } - - @GetMapping("/login") - public String login() { - return "login"; - } -} diff --git a/samples/boot/webflux-form/src/main/java/sample/WebfluxFormApplication.java b/samples/boot/webflux-form/src/main/java/sample/WebfluxFormApplication.java deleted file mode 100644 index 48ddabcdb1..0000000000 --- a/samples/boot/webflux-form/src/main/java/sample/WebfluxFormApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Rob Winch - * @since 5.0 - */ -@SpringBootApplication -public class WebfluxFormApplication { - - public static void main(String[] args) { - SpringApplication.run(WebfluxFormApplication.class, args); - } -} diff --git a/samples/boot/webflux-form/src/main/java/sample/WebfluxFormSecurityConfig.java b/samples/boot/webflux-form/src/main/java/sample/WebfluxFormSecurityConfig.java deleted file mode 100644 index 94642742dc..0000000000 --- a/samples/boot/webflux-form/src/main/java/sample/WebfluxFormSecurityConfig.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.web.server.SecurityWebFilterChain; - -import static org.springframework.security.config.Customizer.withDefaults; - -/** - * @author Rob Winch - * @since 5.0 - */ -@EnableWebFluxSecurity -public class WebfluxFormSecurityConfig { - - @Bean - public MapReactiveUserDetailsService userDetailsService() { - UserDetails user = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("USER") - .build(); - return new MapReactiveUserDetailsService(user); - } - - @Bean - SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - http - .authorizeExchange((exchanges) -> - exchanges - .pathMatchers("/login").permitAll() - .anyExchange().authenticated() - ) - .httpBasic(withDefaults()) - .formLogin((formLogin) -> - formLogin - .loginPage("/login") - ); - return http.build(); - } -} diff --git a/samples/boot/webflux-form/src/main/resources/logback.xml b/samples/boot/webflux-form/src/main/resources/logback.xml deleted file mode 100644 index 3ebbcc0ddd..0000000000 --- a/samples/boot/webflux-form/src/main/resources/logback.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - diff --git a/samples/boot/webflux-form/src/main/resources/templates/index.html b/samples/boot/webflux-form/src/main/resources/templates/index.html deleted file mode 100644 index 992450d43f..0000000000 --- a/samples/boot/webflux-form/src/main/resources/templates/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Secured - - - -
-

Secured

- -
- -
-
- - diff --git a/samples/boot/webflux-form/src/main/resources/templates/login.html b/samples/boot/webflux-form/src/main/resources/templates/login.html deleted file mode 100644 index 4fa5c65688..0000000000 --- a/samples/boot/webflux-form/src/main/resources/templates/login.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - Please Log In - - - - -
- -
- - diff --git a/samples/boot/webflux-x509/spring-security-samples-boot-webflux-x509.gradle b/samples/boot/webflux-x509/spring-security-samples-boot-webflux-x509.gradle deleted file mode 100644 index 57196d2b2b..0000000000 --- a/samples/boot/webflux-x509/spring-security-samples-boot-webflux-x509.gradle +++ /dev/null @@ -1,11 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-security-core') - compile project(':spring-security-config') - compile project(':spring-security-web') - compile 'org.springframework.boot:spring-boot-starter-webflux' - - testCompile project(':spring-security-test') - testCompile 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/samples/boot/webflux-x509/src/main/java/sample/MeController.java b/samples/boot/webflux-x509/src/main/java/sample/MeController.java deleted file mode 100644 index 7c10c6aedf..0000000000 --- a/samples/boot/webflux-x509/src/main/java/sample/MeController.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.security.core.context.ReactiveSecurityContextHolder; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Mono; - -/** - * @author Alexey Nesterov - * @since 5.2 - */ -@RestController -@RequestMapping("/me") -public class MeController { - - @GetMapping - public Mono me() { - return ReactiveSecurityContextHolder.getContext() - .map(SecurityContext::getAuthentication) - .map((authentication) -> "Hello, " + authentication.getName()); - } -} diff --git a/samples/boot/webflux-x509/src/main/java/sample/WebfluxX509Application.java b/samples/boot/webflux-x509/src/main/java/sample/WebfluxX509Application.java deleted file mode 100644 index 89813d073b..0000000000 --- a/samples/boot/webflux-x509/src/main/java/sample/WebfluxX509Application.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.core.userdetails.ReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.web.server.SecurityWebFilterChain; - -import static org.springframework.security.config.Customizer.withDefaults; - -/** - * @author Alexey Nesterov - * @since 5.2 - */ -@SpringBootApplication -public class WebfluxX509Application { - - @Bean - public ReactiveUserDetailsService reactiveUserDetailsService() { - return new MapReactiveUserDetailsService( - User.withUsername("client").password("").authorities("ROLE_USER").build() - ); - } - - @Bean - public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - // @formatter:off - http - .x509(withDefaults()) - .authorizeExchange((exchanges) -> - exchanges - .anyExchange().authenticated() - ); - // @formatter:on - - return http.build(); - } - - public static void main(String[] args) { - SpringApplication.run(WebfluxX509Application.class); - } -} diff --git a/samples/boot/webflux-x509/src/main/resources/application.yml b/samples/boot/webflux-x509/src/main/resources/application.yml deleted file mode 100644 index cdeb85fa7b..0000000000 --- a/samples/boot/webflux-x509/src/main/resources/application.yml +++ /dev/null @@ -1,8 +0,0 @@ -server: - port: 8443 - ssl: - key-store: 'classpath:./certs/server.p12' - key-store-password: 'password' - client-auth: need - trust-store: 'classpath:./certs/server.p12' - trust-store-password: 'password' diff --git a/samples/boot/webflux-x509/src/main/resources/certs/curl_app.sh b/samples/boot/webflux-x509/src/main/resources/certs/curl_app.sh deleted file mode 100644 index dbf7af4b43..0000000000 --- a/samples/boot/webflux-x509/src/main/resources/certs/curl_app.sh +++ /dev/null @@ -1,2 +0,0 @@ - curl -vvvv --cacert out/DevCA.crt --cert out/localhost.crt --key out/localhost.key https://localhost:8443/me - diff --git a/samples/boot/webflux-x509/src/main/resources/certs/server.p12 b/samples/boot/webflux-x509/src/main/resources/certs/server.p12 deleted file mode 100644 index ec536b2f6007eac9486c0daada114fe1faf4facd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5255 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 diff --git a/samples/boot/webflux-x509/src/test/java/sample/WebfluxX509ApplicationTest.java b/samples/boot/webflux-x509/src/test/java/sample/WebfluxX509ApplicationTest.java deleted file mode 100644 index e6ed9cf200..0000000000 --- a/samples/boot/webflux-x509/src/test/java/sample/WebfluxX509ApplicationTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import io.netty.handler.ssl.ClientAuth; -import io.netty.handler.ssl.SslContextBuilder; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.core.io.ClassPathResource; -import org.springframework.http.client.reactive.ClientHttpConnector; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.netty.http.client.HttpClient; - -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.UnrecoverableEntryException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class WebfluxX509ApplicationTest { - - @LocalServerPort - int port; - - @Test - public void shouldExtractAuthenticationFromCertificate() throws Exception { - WebTestClient webTestClient = createWebTestClientWithClientCertificate(); - webTestClient - .get().uri("/me") - .exchange() - .expectStatus().isOk() - .expectBody() - .consumeWith((result) -> { - String responseBody = new String(result.getResponseBody()); - assertThat(responseBody).contains("Hello, client"); - }); - } - - private WebTestClient createWebTestClientWithClientCertificate() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableEntryException { - ClassPathResource serverKeystore = new ClassPathResource("/certs/server.p12"); - - KeyStore keyStore = KeyStore.getInstance("PKCS12"); - keyStore.load(serverKeystore.getInputStream(), "password".toCharArray()); - - X509Certificate devCA = (X509Certificate) keyStore.getCertificate("DevCA"); - - X509Certificate clientCrt = (X509Certificate) keyStore.getCertificate("client"); - KeyStore.Entry keyStoreEntry = keyStore.getEntry("client", - new KeyStore.PasswordProtection("password".toCharArray())); - PrivateKey clientKey = ((KeyStore.PrivateKeyEntry) keyStoreEntry).getPrivateKey(); - - SslContextBuilder sslContextBuilder = SslContextBuilder - .forClient().clientAuth(ClientAuth.REQUIRE) - .trustManager(devCA) - .keyManager(clientKey, clientCrt); - - HttpClient httpClient = HttpClient.create().secure((sslContextSpec) -> sslContextSpec.sslContext(sslContextBuilder)); - ClientHttpConnector httpConnector = new ReactorClientHttpConnector(httpClient); - - return WebTestClient - .bindToServer(httpConnector) - .baseUrl("https://localhost:" + port) - .build(); - } -} diff --git a/samples/certificates/Readme.txt b/samples/certificates/Readme.txt deleted file mode 100644 index 64b415cf83..0000000000 --- a/samples/certificates/Readme.txt +++ /dev/null @@ -1,10 +0,0 @@ -This directory contains certificates and keys for use with SSL in the sample applications. Certificates are issued by -our "Spring Security Test CA" certificate authority. - -ca.pem - the certificate authority's certificate. -server.jks - Java keystore containing the server certificate and privatekey. It Also contains the certificate authority - file and this is used as both keystore and truststore for they jetty server when running the samples with - the maven jetty plugin ("mvn jetty:run"). - -rod.p12, dianne.p12, scott.p12 are all certificate/key combinations for client authentication and can be installed in -your browser if you want to try out support for X.509 authentication. \ No newline at end of file diff --git a/samples/certificates/ca.pem b/samples/certificates/ca.pem deleted file mode 100644 index a5b52ca9d7..0000000000 --- a/samples/certificates/ca.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDojCCAoqgAwIBAgIEMKX1dzANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMC -R0IxETAPBgNVBAgTCFNjb3RsYW5kMRAwDgYDVQQHEwdHbGFzZ293MRkwFwYDVQQK -ExBTcHJpbmcgRnJhbWV3b3JrMRgwFgYDVQQLEw9TcHJpbmcgU2VjdXJpdHkxIDAe -BgNVBAMTF1NwcmluZyBTZWN1cml0eSBUZXN0IENBMB4XDTA4MDEyNTExMTIyMVoX -DTE4MDIyNTAwMDAwMFowgYkxCzAJBgNVBAYTAkdCMREwDwYDVQQIEwhTY290bGFu -ZDEQMA4GA1UEBxMHR2xhc2dvdzEZMBcGA1UEChMQU3ByaW5nIEZyYW1ld29yazEY -MBYGA1UECxMPU3ByaW5nIFNlY3VyaXR5MSAwHgYDVQQDExdTcHJpbmcgU2VjdXJp -dHkgVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALzl/wEe -snYrwqaGZuB8hmwACtptazh1+eXCfd66FkioxlLF7yTnjCC7DT+vmMgSuThIEIsN -xlxLpEgyU3bU8GIuR8wyYIyvuSMcptdFJLV7NKYuRycxpDuqimTM7Br0nfNgKVEv -1QwguGWr6YN3aZ68/xe/D5xyPhakKu++7VFXIXw9f0+nqojdrFTqQ6l9GAVRgfX6 -h4JOaV1VFx83y2pnFj0iFneVxRcvXyWnyXlcOvJDIyVuyS/hYxb+E5rtBvp5XQ0o -5CP4OMwCZGx/jEqlL8oO7BwEgu9aEBxKvoIKJmHDTHgWIxgawTrKabmong4utnMI -yNrhsI77bmh2U7UCAwEAAaMQMA4wDAYDVR0PBAUDAwcGADANBgkqhkiG9w0BAQUF -AAOCAQEAuD8W9Ukkfyi0y65mwguFVAqBC3RSTMRXcjbLQV4rMDM/Q9kjA6acY4Ta -WgxGTwNCydqaqwDVsmn+6Je8Lp2xm9KLDLypVdNopGs+Mlfo55dhwqymXkQw1oJI -CPhR3nBmGEnSWW0UY9bPlpxRF2D5GDVwpuxDtXvWa4baPwRRI9MxwPWHA3ITl+fc -s9QVKy+pRAnuP9MSIp755cJ1CODOn2ElNCqnxxsZmcWcmI3LkHAwTmegl3PVvhrk -MKMEA/neshh/M/hWGNTFt77Hoa7pU9dv5RCWFvZPqsUgPrwGrmUvcmSDir3lSWQm -SuSED2LKVo+BFqwWS+jp49AR9b8B/Q== ------END CERTIFICATE----- diff --git a/samples/certificates/dianne.p12 b/samples/certificates/dianne.p12 deleted file mode 100755 index 6e5ba218db795c356e8c0aa5df637950e500f0d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1768 zcmV5p{H z@KGyZKM(YpXP|$!v=Z`&r_}of`Hb?dr|>EbzZ4AhI-Nr;UQ?jW$?E5B6&9x`m`5+x zek#|fKrRTLbQ*oAytH6XaiRoX#gXQ?<=~KhZ5>Ag*ytt`O5QApHH8t-nA=6|e4=*fKBLsjiY`aqwZ99UdyRcme`|(LamO0j1KRDNa5r_WH!UNrozVe$oMe*=n}Y#T-2Ql` zHrX1ab=Y|UDd zBW`LABJuJ%A-}^jpUv}td4d_BIBru*DA4Q9JG-^UJ9`&`lWBDq`569@ERD6Fpim4z z&Dr(QE_a4~qS8?md%GDQD;cS(OqPr>8xV7-Y7a`Z!52-3mDHX}$op?LWXED^^samlV-=MOuNbUPg-t9P5Mq@ zQ(vaiSG~FTD_sie|1^6yp0c4%8^V(OXe%zFa7aM+N$J-6*fJ-8--}&xXoyMpQ?ZNQ zaH?dq{MI;85ahEj1fh0<$=NLx@hydrwzOjHbBt8s6MB*`%=D{Ne1FzWTsKM0Vj|rL zadQ-`4-lmxuH%#GNl}aQsRTDnuo<$d+xdUD=pnEnCsZ_^ioO?~+5%T~%+d74-e2W{ zGIf!O1O!Z_RpD~0qa9{dB`ttSZROgKDjbuRs>c`5Ja1qZcXR*iDX#?>JL(ls(}IAt}LNVB08P}3Hl5Qwdq zO_Q@DL&%3ZT2XZ(Nzs3Z=Bqn0MeJI$!tymlL9aaUj}+#5iww?vCnq7u9KFk1#Co-^ z1eUU3a6te#K@q{o6p(>t+BqSKtpa^cy#?@bUw;HRWL4EplIOw4B>4>4@+t!0fPry2 zR*-tiB8Nj?-60br)p5xkFzTndzS<5kynQEmxj07I_?(Zw0EUV&b%`cwI60 zFgY+GFbM_)D-Ht!8U+9Z6!ipAu_Xa(fBcQjzWJh!5SV serial.txt -openssl x509 -CA ca.crt -passin pass:changeit -CAkey ca.key -CAserial serial.txt -req -in tomcat.csr -out tomcat.cer -days 36500 -rm serial.txt -keytool -storepass changeit -import -alias ca -file ca.crt -keytool -storepass changeit -import -alias tomcat -file tomcat.cer diff --git a/samples/certificates/localhost-with-ca/tomcat.cer b/samples/certificates/localhost-with-ca/tomcat.cer deleted file mode 100644 index f0569b6602..0000000000 --- a/samples/certificates/localhost-with-ca/tomcat.cer +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICkjCCAfsCAQMwDQYJKoZIhvcNAQEFBQAwPjELMAkGA1UEBhMCVVMxCzAJBgNV -BAgMAkNBMRAwDgYDVQQKDAdQaXZvdGFsMRAwDgYDVQQDDAdQaXZvdGFsMCAXDTEz -MDgwMTE0MzU1MVoYDzIxMTMwNzA4MTQzNTUxWjBfMQswCQYDVQQGEwJVUzELMAkG -A1UECBMCTU8xCzAJBgNVBAcTAktDMREwDwYDVQQKEwhTZWN1cml0eTEPMA0GA1UE -CxMGU3ByaW5nMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQCKCyVI5D4h0lWU9D40P0kHkADWONRLQ9o0fcQvJmQaLwJN -tL0KpDiAwXiot4KKZWMGmYKoFtvhnd/t7ybZsODqsImDCZjKKvHaMTpFOyrl9SHW -PT7bvt7jBL47QqL/UJ0bApxVMmLD0DhcOmTkMmzm932F/he9w5z1nIsVl4POX+hQ -yyuuS+AvZdnUr5W2+COsvI1hsibrpnUnIvcXPHmSVrl4kD16OJ3Z/8Baia4mC3sy -pxqXCiBUeWbDsR5s9tZtMOJH7PpDbLsxGR3Zely4xWx7fmn/lW57EFyhMjXWZfUH -pTRsPWlFEYdTdnyM00MWWXrt+Y3kW9mb3w2DCf2fAgMBAAEwDQYJKoZIhvcNAQEF -BQADgYEAR1Y5IIfRrFIKTOc7gx4X2IOyByNdMYfd1+CWnEycUNuFwCE5iBJAbyN6 -yy2kViSFuTHwyJVD49QJNiFXOKZYmE8EFke1Y3nxwwe9MqfeTsrHpYGtpSZwDzv9 -64UM0qOPWxt+P9txQShcokldSt8BZ4iOJ9G6yY5EQdswE6rGkts= ------END CERTIFICATE----- diff --git a/samples/certificates/localhost-with-ca/tomcat.csr b/samples/certificates/localhost-with-ca/tomcat.csr deleted file mode 100644 index e6bbf82116..0000000000 --- a/samples/certificates/localhost-with-ca/tomcat.csr +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN NEW CERTIFICATE REQUEST----- -MIIC1DCCAbwCAQAwXzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1PMQswCQYDVQQHEwJLQzERMA8G -A1UEChMIU2VjdXJpdHkxDzANBgNVBAsTBlNwcmluZzESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAigslSOQ+IdJVlPQ+ND9JB5AA1jjUS0PaNH3ELyZk -Gi8CTbS9CqQ4gMF4qLeCimVjBpmCqBbb4Z3f7e8m2bDg6rCJgwmYyirx2jE6RTsq5fUh1j0+277e -4wS+O0Ki/1CdGwKcVTJiw9A4XDpk5DJs5vd9hf4XvcOc9ZyLFZeDzl/oUMsrrkvgL2XZ1K+Vtvgj -rLyNYbIm66Z1JyL3Fzx5kla5eJA9ejid2f/AWomuJgt7MqcalwogVHlmw7EebPbWbTDiR+z6Q2y7 -MRkd2XpcuMVse35p/5VuexBcoTI11mX1B6U0bD1pRRGHU3Z8jNNDFll67fmN5FvZm98Ngwn9nwID -AQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUpQODsrGvfB6TWTCIEEdx0OKB1+QwDQYJ -KoZIhvcNAQELBQADggEBACL6M4Htn6tEebOH8vj3R8cVcgebxshQV/KD7+tWUq2RSno4JndsYxEF -H3Zh3vWhh5Q0nH55s1C/kiKYNP0jQXheeAiH6hatiCpSssgvDnw653ivBgqT3mo8sy1jpw9Pdx7F -6JuCksus+aI9PUKuI3DXXyAxKJfc/JmnnCXsyZz8sVu66bMrIel0kAODN6Da35QohDuStNuplu/R -ZHoiapQi3dxmWctC30fz0y7xqRVbRUKWHE7YWXqtWjFusUjXtZJobMeEb6DLeFfRsJ50OG8kgyZy -TvWQ9kP3ODeDqq74xiy7NxwGH8ytsWEwpSC10Z35vWb++rtl963A2itoK4E= ------END NEW CERTIFICATE REQUEST----- diff --git a/samples/certificates/rod.p12 b/samples/certificates/rod.p12 deleted file mode 100755 index 4cd05644305bc4f37fed7284e3faec8d759ca607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1784 zcmV+o2 z-1XypCipPV7v>@v0s;rnfPw}{P0Qr^yXYqvT)0wdjn7_cF52x95Oum`$&>QN;=3#q z@`4M4;%4QY6a=|1;@)l61OH1h3w2=4eQnPgJ@9_BRARM;H&rr-u!|iO^ z-E8aj3m=dQq&VCR@CO9}lU+z>(2G1^#V5Kst5$o(AFAYGwCkI^UjVR1OQVVAwjk-H zAE9(>sVC=|b(?wjWeEVzTR1hje5ZppIDtS%`xQuNw^Bh`ANJS&laAthnC$kBEEKY{ z2$c^;R-mO=Gci2~qCL>lAap+21e-M2B#s+53>!G`r2py!64;I%u>;y=vFbxPb9)h$nB%`rU-WSJ0t9G5jUGUlQG*IWxIvdew+eE ze67)6c(La76p_b6+K?pMYZQ1;t+o7vTmA^K!ScMD1gFjL4g!qsv815H$~=UcDQQjy zpib=DS-P_8lT}`C`R(&Y&MR(v)g=#*DZ(iLQyF##`$jOtQy18~i3xyg zaPvkmh~n7pk2?X2tc!_8nhX*DV=7zn^0Cv$WKC^v>a(jwXjHL^_w1($T`FMK^WIA0E6-Ibk7ftz43C-`B&E{yD2?`0T zQEXfKGg$y0eS;giVVT{@C;)^XrH)BHOc+5lxc?5O!}$ zlKck=be#ttIhf<64I^+n6Eq)$g>Bn}RX{?)b5g%e+QY2@_Kb?JqmKV+>OP%YGByf9 z(NSP7R#I#WAB%3N!;L6L57LEM1I1|VT6J$^pV@_yM2%33RnRTLCa+(ba3WwO6>g;4 z1VowM!(_>Ybrov|&JkP9W3}&c&U8XaNY>$c&d!3x-K;SJp4NFa&lWE3r2 zRY&>|Pc%LPYZM#F_{W-ECA%_3n*asGOy{QYiV`K*%6y~0(IkuVc{@8yw25y0I1dZp zNMQLOJ6X9(VqW%5LJ8~}bC+<{;U>Y4aS^^onQEX`E)LeTOdC`iwYp)&jAHe`O`?jm zQP74kvy8Q>sQOeYY-3{Xpn5M98QpNJ<;{tzB$l+92uBqbW&@%^N*5x#z&%KFMiYzS z51z3d;%f|LzHAClqV9B^-}cqq<#e-z#`5f6G}b70bg3p0@EJNA2x%BD`$-ul#xTOP z-W+%j7-*-t@p(0-{o+*M0sO5IAD^BF-vq7dF#&>vd!A`6ahmFYHObXCjtW6;m^JJg z&pWU`?~Z~g5~og{5sD2fi?_(wh5L9@RO-Qo3a=j&h|G0dHy^# zKdl2rJ=d>EghhIf^1m|%7oV{#uQc`}6%Whxo)tlWQt)xpD3SYR*3=Ha2nMX)FgY+GFbM_)D-Ht!8U+9Z6h0=3+$Ga8{-?Rpwy}ec8W~cY aA_Ne)6!9W(f=}drPhM~u0`Xu10te84%1hP& diff --git a/samples/certificates/scott.p12 b/samples/certificates/scott.p12 deleted file mode 100644 index f0a6357e730752bd6b2f05658ec8a1a85ade6de9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1768 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 diff --git a/samples/javaconfig/aspectj/spring-security-samples-javaconfig-aspectj.gradle b/samples/javaconfig/aspectj/spring-security-samples-javaconfig-aspectj.gradle deleted file mode 100644 index 6487a14d43..0000000000 --- a/samples/javaconfig/aspectj/spring-security-samples-javaconfig-aspectj.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample' -apply plugin: 'io.freefair.aspectj.post-compile-weaving' - -repositories { - mavenCentral() -} - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-core') - - aspect project(':spring-security-aspects') - - runtime project(':spring-security-aspects') -} - -aspectj { - version = aspectjVersion -} - diff --git a/samples/javaconfig/aspectj/src/main/java/sample/aspectj/AspectjSecurityConfig.java b/samples/javaconfig/aspectj/src/main/java/sample/aspectj/AspectjSecurityConfig.java deleted file mode 100644 index 038b8271f3..0000000000 --- a/samples/javaconfig/aspectj/src/main/java/sample/aspectj/AspectjSecurityConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.aspectj; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AdviceMode; -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; - -/** - * @author Rob Winch - */ -@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, securedEnabled = true) -public class AspectjSecurityConfig { - @Bean - public Service service() { - return new Service(); - } - - @Bean - public SecuredService securedService() { - return new SecuredService(); - } - - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication(); - } -} diff --git a/samples/javaconfig/aspectj/src/main/java/sample/aspectj/SecuredService.java b/samples/javaconfig/aspectj/src/main/java/sample/aspectj/SecuredService.java deleted file mode 100644 index 9f81cf1733..0000000000 --- a/samples/javaconfig/aspectj/src/main/java/sample/aspectj/SecuredService.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.aspectj; - -import org.springframework.security.access.annotation.Secured; - -/** - * Service which is secured on the class level - * - * @author Mike Wiesner - * @since 3.0 - */ -@Secured("ROLE_USER") -public class SecuredService { - - public void secureMethod() { - // nothing - } - -} diff --git a/samples/javaconfig/aspectj/src/main/java/sample/aspectj/Service.java b/samples/javaconfig/aspectj/src/main/java/sample/aspectj/Service.java deleted file mode 100644 index 70b8c0c71f..0000000000 --- a/samples/javaconfig/aspectj/src/main/java/sample/aspectj/Service.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.aspectj; - -import org.springframework.security.access.annotation.Secured; - -/** - * Service which is secured on method level - * - * @author Mike Wiesner - * @since 1.0 - */ -public class Service { - - @Secured("ROLE_USER") - public void secureMethod() { - // nothing - } - - public void publicMethod() { - // nothing - } - -} diff --git a/samples/javaconfig/aspectj/src/test/java/sample/aspectj/AspectJInterceptorTests.java b/samples/javaconfig/aspectj/src/test/java/sample/aspectj/AspectJInterceptorTests.java deleted file mode 100644 index 344de63e11..0000000000 --- a/samples/javaconfig/aspectj/src/test/java/sample/aspectj/AspectJInterceptorTests.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.aspectj; - -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; - - -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import java.lang.reflect.Proxy; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = AspectjSecurityConfig.class) -public class AspectJInterceptorTests { - private Authentication admin = new UsernamePasswordAuthenticationToken("test", "xxx", - AuthorityUtils.createAuthorityList("ROLE_ADMIN")); - private Authentication user = new UsernamePasswordAuthenticationToken("test", "xxx", - AuthorityUtils.createAuthorityList("ROLE_USER")); - - @Autowired - private Service service; - - @Autowired - private SecuredService securedService; - - @Test - public void publicMethod() { - service.publicMethod(); - } - - @Test(expected = AuthenticationCredentialsNotFoundException.class) - public void securedMethodNotAuthenticated() { - service.secureMethod(); - } - - @Test(expected = AccessDeniedException.class) - public void securedMethodWrongRole() { - SecurityContextHolder.getContext().setAuthentication(admin); - service.secureMethod(); - } - - @Test - public void securedMethodEverythingOk() { - SecurityContextHolder.getContext().setAuthentication(user); - service.secureMethod(); - } - - @Test(expected = AuthenticationCredentialsNotFoundException.class) - public void securedClassNotAuthenticated() { - securedService.secureMethod(); - } - - @Test(expected = AccessDeniedException.class) - public void securedClassWrongRole() { - SecurityContextHolder.getContext().setAuthentication(admin); - securedService.secureMethod(); - } - - @Test(expected = AccessDeniedException.class) - public void securedClassWrongRoleOnNewedInstance() { - SecurityContextHolder.getContext().setAuthentication(admin); - new SecuredService().secureMethod(); - } - - @Test - public void securedClassEverythingOk() { - SecurityContextHolder.getContext().setAuthentication(user); - securedService.secureMethod(); - new SecuredService().secureMethod(); - } - - // SEC-2595 - @Test - public void notProxy() { - assertThat(Proxy.isProxyClass(securedService.getClass())).isFalse(); - } - - @After - public void tearDown() { - SecurityContextHolder.clearContext(); - } -} diff --git a/samples/javaconfig/aspectj/src/test/resources/logback-test.xml b/samples/javaconfig/aspectj/src/test/resources/logback-test.xml deleted file mode 100644 index 2d51ba4180..0000000000 --- a/samples/javaconfig/aspectj/src/test/resources/logback-test.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - diff --git a/samples/javaconfig/concurrency/spring-security-samples-javaconfig-concurrency.gradle b/samples/javaconfig/concurrency/spring-security-samples-javaconfig-concurrency.gradle deleted file mode 100644 index 7a8e417d8e..0000000000 --- a/samples/javaconfig/concurrency/spring-security-samples-javaconfig-concurrency.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-core') - compile project(':spring-security-samples-javaconfig-messages') - compile project(':spring-security-web') - compile 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api' - compile 'javax.validation:validation-api' - compile 'org.hibernate:hibernate-validator' - compile 'org.springframework:spring-jdbc' - compile 'org.springframework:spring-webmvc' - compile slf4jDependencies - - providedCompile 'javax.servlet.jsp:javax.servlet.jsp-api' - providedCompile 'javax.servlet:javax.servlet-api:3.0.1' - - runtime 'ch.qos.logback:logback-classic' - runtime 'opensymphony:sitemesh' -} diff --git a/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java b/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java deleted file mode 100644 index c33dc58cf2..0000000000 --- a/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config; - -import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; -import org.springframework.security.web.session.HttpSessionEventPublisher; - -/** - * We customize {@link AbstractSecurityWebApplicationInitializer} to enable the - * {@link HttpSessionEventPublisher}. - * - * @author Rob Winch - */ -public class MessageSecurityWebApplicationInitializer extends - AbstractSecurityWebApplicationInitializer { - - @Override - protected boolean enableHttpSessionEventPublisher() { - return true; - } -} diff --git a/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java deleted file mode 100644 index 45773f3eb7..0000000000 --- a/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -import static org.springframework.security.config.Customizer.withDefaults; - -@EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) -public class SecurityConfig extends WebSecurityConfigurerAdapter { - // @formatter:off - @Autowired - public void configureGlobal( - AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("user").password("password").roles("USER"); - } - // @formatter:on - - // @formatter:off - @Override - protected void configure( - HttpSecurity http) throws Exception { - http - .authorizeRequests((authorizeRequests) -> - authorizeRequests - .anyRequest().authenticated() - ) - .formLogin(withDefaults()) - .sessionManagement((sessionManagement) -> - sessionManagement - .sessionConcurrency((sessionConcurrency) -> - sessionConcurrency - .maximumSessions(1) - .expiredUrl("/login?expired") - ) - ); - } - // @formatter:on -} diff --git a/samples/javaconfig/concurrency/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java b/samples/javaconfig/concurrency/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java deleted file mode 100644 index dd807f16d1..0000000000 --- a/samples/javaconfig/concurrency/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -/** - * @author Rob Winch - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = SecurityConfig.class) -public class SecurityConfigTests { - - @Test - public void securityConfigurationLoads() { - } -} diff --git a/samples/javaconfig/data/spring-security-samples-javaconfig-data.gradle b/samples/javaconfig/data/spring-security-samples-javaconfig-data.gradle deleted file mode 100644 index 94680d9b97..0000000000 --- a/samples/javaconfig/data/spring-security-samples-javaconfig-data.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-data') - compile 'javax.validation:validation-api' - compile 'org.eclipse.persistence:javax.persistence' - compile 'org.hibernate:hibernate-entitymanager' - compile 'org.hibernate:hibernate-validator' - compile 'org.hsqldb:hsqldb' - compile 'org.springframework.data:spring-data-jpa' -} diff --git a/samples/javaconfig/data/src/main/java/samples/DataConfig.java b/samples/javaconfig/data/src/main/java/samples/DataConfig.java deleted file mode 100644 index cd401a5df4..0000000000 --- a/samples/javaconfig/data/src/main/java/samples/DataConfig.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package samples; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; -import org.springframework.core.io.ClassPathResource; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; -import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; -import org.springframework.orm.jpa.JpaTransactionManager; -import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; -import org.springframework.orm.jpa.vendor.Database; -import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; -import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; -import org.springframework.transaction.PlatformTransactionManager; -import samples.data.Message; - -import javax.sql.DataSource; - -/** - * @author Rob Winch - */ -@Configuration -@ComponentScan -@EnableJpaRepositories -public class DataConfig { - - @Bean - public SecurityEvaluationContextExtension expressionEvaluationContextProvider() { - return new SecurityEvaluationContextExtension(); - } - - @Bean - public DataSource dataSource() { - EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); - return builder.setType(EmbeddedDatabaseType.HSQL).build(); - } - - @Bean - public LocalContainerEntityManagerFactoryBean entityManagerFactory() { - HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); - vendorAdapter.setDatabase(Database.HSQL); - vendorAdapter.setGenerateDdl(true); - - LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); - factory.setJpaVendorAdapter(vendorAdapter); - factory.setPackagesToScan(Message.class.getPackage().getName()); - factory.setDataSource(dataSource()); - - return factory; - } - - @Bean - @DependsOn("entityManagerFactory") - public ResourceDatabasePopulator initDatabase(DataSource dataSource) throws Exception { - ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); - populator.addScript(new ClassPathResource("data.sql")); - populator.populate(dataSource.getConnection()); - return populator; - } - - @Bean - public PlatformTransactionManager transactionManager() { - JpaTransactionManager txManager = new JpaTransactionManager(); - txManager.setEntityManagerFactory(entityManagerFactory().getObject()); - return txManager; - } -} diff --git a/samples/javaconfig/data/src/main/java/samples/data/Message.java b/samples/javaconfig/data/src/main/java/samples/data/Message.java deleted file mode 100644 index 7c567e9c12..0000000000 --- a/samples/javaconfig/data/src/main/java/samples/data/Message.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package samples.data; - -import java.util.Calendar; - -import javax.persistence.*; - -import org.hibernate.validator.constraints.NotEmpty; - -@Entity -public class Message { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - - @NotEmpty(message = "Message is required.") - private String text; - - @NotEmpty(message = "Summary is required.") - private String summary; - - private Calendar created = Calendar.getInstance(); - - @OneToOne - private User to; - - public User getTo() { - return to; - } - - public void setTo(User to) { - this.to = to; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Calendar getCreated() { - return created; - } - - public void setCreated(Calendar created) { - this.created = created; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public String getSummary() { - return summary; - } - - public void setSummary(String summary) { - this.summary = summary; - } -} diff --git a/samples/javaconfig/data/src/main/java/samples/data/MessageRepository.java b/samples/javaconfig/data/src/main/java/samples/data/MessageRepository.java deleted file mode 100644 index c98a1d3fde..0000000000 --- a/samples/javaconfig/data/src/main/java/samples/data/MessageRepository.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package samples.data; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * @author Rob Winch - */ -@Repository -public interface MessageRepository extends JpaRepository { -} diff --git a/samples/javaconfig/data/src/main/java/samples/data/SecurityMessageRepository.java b/samples/javaconfig/data/src/main/java/samples/data/SecurityMessageRepository.java deleted file mode 100644 index f6b2ac956d..0000000000 --- a/samples/javaconfig/data/src/main/java/samples/data/SecurityMessageRepository.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package samples.data; - -import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Repository; - -import java.util.List; - -/** - * @author Rob Winch - */ -@Repository -public interface SecurityMessageRepository extends MessageRepository { - @Query("select m from Message m where m.to.id = ?#{ principal?.id }") - List findAll(); -} \ No newline at end of file diff --git a/samples/javaconfig/data/src/main/java/samples/data/User.java b/samples/javaconfig/data/src/main/java/samples/data/User.java deleted file mode 100644 index 15d4f37d77..0000000000 --- a/samples/javaconfig/data/src/main/java/samples/data/User.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package samples.data; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; - -/** - * @author Rob Winch - */ -@Entity -public class User { - @GeneratedValue(strategy = GenerationType.AUTO) - @Id - private Long id; - - private String firstName; - - private String lastName; - - private String email; - - private String password; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } -} \ No newline at end of file diff --git a/samples/javaconfig/data/src/test/java/samples/data/SecurityMessageRepositoryTests.java b/samples/javaconfig/data/src/test/java/samples/data/SecurityMessageRepositoryTests.java deleted file mode 100644 index 9972659fd2..0000000000 --- a/samples/javaconfig/data/src/test/java/samples/data/SecurityMessageRepositoryTests.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package samples.data; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import samples.DataConfig; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Rob Winch - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = DataConfig.class) -public class SecurityMessageRepositoryTests { - @Autowired - SecurityMessageRepository repository; - - User user; - - @Before - public void setup() { - user = new User(); - user.setId(0L); - List authorities = AuthorityUtils - .createAuthorityList("ROLE_USER"); - UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( - user, "notused", authorities); - SecurityContextHolder.getContext().setAuthentication(authentication); - } - - @After - public void cleanup() { - SecurityContextHolder.clearContext(); - } - - @Test - public void findAllOnlyToCurrentUser() { - Long expectedId = user.getId(); - List messages = repository.findAll(); - assertThat(messages).hasSize(3); - for (Message m : messages) { - assertThat(m.getTo().getId()).isEqualTo(expectedId); - } - } -} diff --git a/samples/javaconfig/data/src/test/resources/data.sql b/samples/javaconfig/data/src/test/resources/data.sql deleted file mode 100644 index 97c60b155b..0000000000 --- a/samples/javaconfig/data/src/test/resources/data.sql +++ /dev/null @@ -1,10 +0,0 @@ -insert into user(id,email,password,firstName,lastName) values (0,'rob@example.com','password','Rob','Winch'); -insert into user(id,email,password,firstName,lastName) values (1,'luke@example.com','password','Luke','Taylor'); - -insert into message(id,created,to_id,summary,text) values (100,'2014-07-10 10:00:00',0,'Hello Rob','This message is for Rob'); -insert into message(id,created,to_id,summary,text) values (101,'2014-07-10 14:00:00',0,'How are you Rob?','This message is for Rob'); -insert into message(id,created,to_id,summary,text) values (102,'2014-07-11 22:00:00',0,'Is this secure?','This message is for Rob'); - -insert into message(id,created,to_id,summary,text) values (110,'2014-07-12 10:00:00',1,'Hello Luke','This message is for Luke'); -insert into message(id,created,to_id,summary,text) values (111,'2014-07-12 10:00:00',1,'Greetings Luke','This message is for Luke'); -insert into message(id,created,to_id,summary,text) values (112,'2014-07-12 10:00:00',1,'Is this secure?','This message is for Luke'); \ No newline at end of file diff --git a/samples/javaconfig/form/spring-security-samples-javaconfig-form.gradle b/samples/javaconfig/form/spring-security-samples-javaconfig-form.gradle deleted file mode 100644 index 3dee895966..0000000000 --- a/samples/javaconfig/form/spring-security-samples-javaconfig-form.gradle +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-core') - compile project(':spring-security-samples-javaconfig-messages') - compile project(':spring-security-web') - compile 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api' - compile 'javax.validation:validation-api' - compile 'org.hibernate:hibernate-validator' - compile 'org.springframework:spring-webmvc' - compile slf4jDependencies - - compile 'javax.xml.bind:jaxb-api' - compile 'com.sun.xml.bind:jaxb-core' - compile 'com.sun.xml.bind:jaxb-impl' - - providedCompile 'javax.servlet.jsp:javax.servlet.jsp-api' - providedCompile 'javax.servlet:javax.servlet-api' - - runtime 'opensymphony:sitemesh' - - integrationTestCompile seleniumDependencies -} diff --git a/samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/FormJcTests.java b/samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/FormJcTests.java deleted file mode 100644 index 1ca1e669a1..0000000000 --- a/samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/FormJcTests.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import org.springframework.security.samples.pages.HomePage; -import org.springframework.security.samples.pages.LoginPage; - -/** - * @author Michael Simons - */ -public class FormJcTests { - private WebDriver driver; - - private int port; - - @Before - public void setup() { - this.port = Integer.parseInt(System.getProperty("app.httpPort")); - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void accessHomePageWithUnauthenticatedUserSendsToLoginPage() { - final LoginPage loginPage = HomePage.to(this.driver, this.port); - loginPage.assertAt(); - } - - @Test - public void authenticatedUserIsSentToOriginalPage() { - final String userName = "user"; - final HomePage homePage = HomePage.to(this.driver, this.port) - .loginForm() - .username(userName) - .password("password") - .submit(); - homePage - .assertAt() - .andTheUserNameDisplayedIs(userName); - } - - @Test - public void authenticatedUserLogsOut() { - LoginPage loginPage = HomePage.to(this.driver, this.port) - .loginForm() - .username("user") - .password("password") - .submit() - .logout(); - loginPage.assertAt(); - - loginPage = HomePage.to(this.driver, this.port); - loginPage.assertAt(); - } -} diff --git a/samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java b/samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java deleted file mode 100644 index 22ddd1c639..0000000000 --- a/samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/pages/HomePage.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.pages; - -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Michael Simons - */ -public class HomePage { - private final WebDriver webDriver; - - @FindBy(css = "input[type=submit]") - private WebElement logoutButton; - - public static LoginPage to(WebDriver driver, int port) { - driver.get("http://localhost:" + port +"/"); - return PageFactory.initElements(driver, LoginPage.class); - } - - public HomePage(WebDriver webDriver) { - this.webDriver = webDriver; - } - - public Content assertAt() { - assertThat(this.webDriver.getTitle()).isEqualTo("SecureMail: View All"); - return PageFactory.initElements(this.webDriver, Content.class); - } - - public LoginPage logout() { - this.logoutButton.submit(); - return PageFactory.initElements(this.webDriver, LoginPage.class); - } - - public static class Content { - @FindBy(css = "p.navbar-text") - private WebElement message; - - public Content andTheUserNameDisplayedIs(final String userName) { - assertThat(message.getText()).isEqualTo(userName); - return this; - } - } -} diff --git a/samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java b/samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java deleted file mode 100644 index af6fbaa988..0000000000 --- a/samples/javaconfig/form/src/integration-test/java/org/springframework/security/samples/pages/LoginPage.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.pages; - -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Michael Simons - */ -public class LoginPage { - - private final WebDriver webDriver; - - private final LoginForm loginForm; - - public LoginPage(WebDriver webDriver) { - this.webDriver = webDriver; - this.loginForm = PageFactory.initElements(this.webDriver, LoginForm.class); - } - - public LoginPage assertAt() { - assertThat(this.webDriver.getTitle()).isEqualTo("SecureMail: Please Login"); - return this; - } - - public LoginForm loginForm() { - return this.loginForm; - } - - public static class LoginForm { - private WebDriver webDriver; - private WebElement username; - private WebElement password; - @FindBy(css = "button[type=submit]") - private WebElement submit; - - public LoginForm(WebDriver webDriver) { - this.webDriver = webDriver; - } - - public LoginForm username(String username) { - this.username.sendKeys(username); - return this; - } - - public LoginForm password(String password) { - this.password.sendKeys(password); - return this; - } - - public HomePage submit() { - this.submit.click(); - return PageFactory.initElements(this.webDriver, HomePage.class); - } - } -} diff --git a/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java b/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java deleted file mode 100644 index f851f82de0..0000000000 --- a/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config; - -import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; - -/** - * No customizations of {@link AbstractSecurityWebApplicationInitializer} are necessary. - * - * @author Rob Winch - */ -public class MessageSecurityWebApplicationInitializer extends - AbstractSecurityWebApplicationInitializer { -} diff --git a/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java deleted file mode 100644 index 8f9cbba6f6..0000000000 --- a/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.userdetails.User; - -@EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - // @formatter:off - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests((authorizeRequests) -> - authorizeRequests - .antMatchers("/resources/**").permitAll() - .anyRequest().authenticated() - ) - .formLogin((formLogin) -> - formLogin - .loginPage("/login") - .permitAll() - ) - .logout((logout) -> - logout - .permitAll() - ); - } - // @formatter:on - - // @formatter:off - @Autowired - public void configureGlobal( - AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER")); - } - // @formatter:on -} diff --git a/samples/javaconfig/form/src/main/resources/logback.xml b/samples/javaconfig/form/src/main/resources/logback.xml deleted file mode 100644 index 3ebbcc0ddd..0000000000 --- a/samples/javaconfig/form/src/main/resources/logback.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - diff --git a/samples/javaconfig/form/src/main/resources/views/login.html b/samples/javaconfig/form/src/main/resources/views/login.html deleted file mode 100644 index c28c5b2add..0000000000 --- a/samples/javaconfig/form/src/main/resources/views/login.html +++ /dev/null @@ -1,24 +0,0 @@ - - - Please Login - - -

-
-
- Please Login -
Invalid - username and password.
-
You - have been logged out.
- - -
- -
-
-
-
- - \ No newline at end of file diff --git a/samples/javaconfig/form/src/main/webapp/WEB-INF/views/login.jspx b/samples/javaconfig/form/src/main/webapp/WEB-INF/views/login.jspx deleted file mode 100644 index 1f472ba566..0000000000 --- a/samples/javaconfig/form/src/main/webapp/WEB-INF/views/login.jspx +++ /dev/null @@ -1,36 +0,0 @@ - - - - -Please Login - - - - -
- Please Login - -
- Invalid username and password. -
-
- -
- You have been logged out. -
-
- - - - -
- -
-
-
- - -
diff --git a/samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/compose.jspx b/samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/compose.jspx deleted file mode 100644 index a92f7e2d6c..0000000000 --- a/samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/compose.jspx +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Compose - - -
-

Messages : Create

- - - - - - -
- -
-
-
- - -
\ No newline at end of file diff --git a/samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/inbox.jspx b/samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/inbox.jspx deleted file mode 100644 index ed02d313c6..0000000000 --- a/samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/inbox.jspx +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Inbox - - -

Inbox

- - - - - - - - - - - - - - - - - - - - - - - -
CreatedSummary
You have not received any mail yet.
- - -
\ No newline at end of file diff --git a/samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/show.jspx b/samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/show.jspx deleted file mode 100644 index 82007c267b..0000000000 --- a/samples/javaconfig/form/src/main/webapp/WEB-INF/views/messages/show.jspx +++ /dev/null @@ -1,24 +0,0 @@ - - - - - <c:out value="${message.summary}"/> - - -
-

Message :

-
-
Created
-
-
Message
-
-
-
- - -
\ No newline at end of file diff --git a/samples/javaconfig/form/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java b/samples/javaconfig/form/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java deleted file mode 100644 index dd807f16d1..0000000000 --- a/samples/javaconfig/form/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -/** - * @author Rob Winch - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = SecurityConfig.class) -public class SecurityConfigTests { - - @Test - public void securityConfigurationLoads() { - } -} diff --git a/samples/javaconfig/hellojs/spring-security-samples-javaconfig-hellojs.gradle b/samples/javaconfig/hellojs/spring-security-samples-javaconfig-hellojs.gradle deleted file mode 100644 index 86700d410d..0000000000 --- a/samples/javaconfig/hellojs/spring-security-samples-javaconfig-hellojs.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile project(':spring-security-config') - compile project(':spring-security-core') - compile project(':spring-security-samples-javaconfig-messages') - compile project(':spring-security-web') - compile 'com.fasterxml.jackson.core:jackson-databind' - compile 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api' - compile 'javax.validation:validation-api' - compile 'org.hibernate:hibernate-validator' - compile 'org.springframework:spring-jdbc' - compile 'org.springframework:spring-webmvc' - compile slf4jDependencies - - providedCompile 'javax.servlet:javax.servlet-api' - providedCompile 'javax.servlet.jsp:javax.servlet.jsp-api' - - runtime 'opensymphony:sitemesh' -} diff --git a/samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java b/samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java deleted file mode 100644 index f851f82de0..0000000000 --- a/samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config; - -import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; - -/** - * No customizations of {@link AbstractSecurityWebApplicationInitializer} are necessary. - * - * @author Rob Winch - */ -public class MessageSecurityWebApplicationInitializer extends - AbstractSecurityWebApplicationInitializer { -} diff --git a/samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/config/SecurityConfig.java deleted file mode 100644 index 595d2413e0..0000000000 --- a/samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/config/SecurityConfig.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; - -@EnableWebSecurity -public class SecurityConfig { - - // @formatter:off - @Autowired - public void configureGlobal( - AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("user").password("{noop}password").roles("USER"); - } - // @formatter:on -} diff --git a/samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/mvc/MessageJsonController.java b/samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/mvc/MessageJsonController.java deleted file mode 100644 index 696d3c75e7..0000000000 --- a/samples/javaconfig/hellojs/src/main/java/org/springframework/security/samples/mvc/MessageJsonController.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.samples.mvc; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; -import java.util.Optional; - -import javax.validation.Valid; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.samples.data.Message; -import org.springframework.security.samples.data.MessageRepository; -import org.springframework.stereotype.Controller; -import org.springframework.validation.BindingResult; -import org.springframework.validation.ObjectError; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.servlet.mvc.support.RedirectAttributes; - -@Controller -@RequestMapping(value = "/", produces = "application/json") -public class MessageJsonController { - private MessageRepository messageRepository; - - @Autowired - public MessageJsonController(MessageRepository messageRepository) { - this.messageRepository = messageRepository; - } - - @RequestMapping - public ResponseEntity> list() { - Iterable messages = messageRepository.findAll(); - return new ResponseEntity<>(messages, HttpStatus.OK); - } - - @RequestMapping("{id}") - public ResponseEntity> view(@PathVariable Long id) { - Optional message = messageRepository.findById(id); - return new ResponseEntity<>(message, HttpStatus.OK); - } - - @RequestMapping(method = RequestMethod.POST, consumes = "application/json") - public ResponseEntity create(@Valid @RequestBody Message message, - BindingResult result, RedirectAttributes redirect) { - if (result.hasErrors()) { - List errors = new ArrayList<>(result.getErrorCount()); - for (ObjectError r : result.getAllErrors()) { - errors.add(r.getDefaultMessage()); - } - return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); - } - message.setCreated(Calendar.getInstance()); - message = messageRepository.save(message); - return new ResponseEntity<>(message, HttpStatus.OK); - } -} diff --git a/samples/javaconfig/hellojs/src/main/resources/resources/js/bootstrap.js b/samples/javaconfig/hellojs/src/main/resources/resources/js/bootstrap.js deleted file mode 100644 index ee5a14587b..0000000000 --- a/samples/javaconfig/hellojs/src/main/resources/resources/js/bootstrap.js +++ /dev/null @@ -1,2280 +0,0 @@ -/* =================================================== - * bootstrap-transition.js v2.3.2 - * https://twitter.github.com/bootstrap/javascript.html#transitions - * =================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* CSS TRANSITION SUPPORT (https://www.modernizr.com/) - * ======================================================= */ - - $(function () { - - $.support.transition = (function () { - - var transitionEnd = (function () { - - var el = document.createElement('bootstrap') - , transEndEventNames = { - 'WebkitTransition' : 'webkitTransitionEnd' - , 'MozTransition' : 'transitionend' - , 'OTransition' : 'oTransitionEnd otransitionend' - , 'transition' : 'transitionend' - } - , name - - for (name in transEndEventNames){ - if (el.style[name] !== undefined) { - return transEndEventNames[name] - } - } - - }()) - - return transitionEnd && { - end: transitionEnd - } - - })() - - }) - -}(window.jQuery);/* ========================================================== - * bootstrap-alert.js v2.3.2 - * https://twitter.github.com/bootstrap/javascript.html#alerts - * ========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* ALERT CLASS DEFINITION - * ====================== */ - - var dismiss = '[data-dismiss="alert"]' - , Alert = function (el) { - $(el).on('click', dismiss, this.close) - } - - Alert.prototype.close = function (e) { - var $this = $(this) - , selector = $this.attr('data-target') - , $parent - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } - - $parent = $(selector) - - e && e.preventDefault() - - $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) - - $parent.trigger(e = $.Event('close')) - - if (e.isDefaultPrevented()) return - - $parent.removeClass('in') - - function removeElement() { - $parent - .trigger('closed') - .remove() - } - - $.support.transition && $parent.hasClass('fade') ? - $parent.on($.support.transition.end, removeElement) : - removeElement() - } - - - /* ALERT PLUGIN DEFINITION - * ======================= */ - - var old = $.fn.alert - - $.fn.alert = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('alert') - if (!data) $this.data('alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - $.fn.alert.Constructor = Alert - - - /* ALERT NO CONFLICT - * ================= */ - - $.fn.alert.noConflict = function () { - $.fn.alert = old - return this - } - - - /* ALERT DATA-API - * ============== */ - - $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) - -}(window.jQuery);/* ============================================================ - * bootstrap-button.js v2.3.2 - * https://twitter.github.com/bootstrap/javascript.html#buttons - * ============================================================ - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* BUTTON PUBLIC CLASS DEFINITION - * ============================== */ - - var Button = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, $.fn.button.defaults, options) - } - - Button.prototype.setState = function (state) { - var d = 'disabled' - , $el = this.$element - , data = $el.data() - , val = $el.is('input') ? 'val' : 'html' - - state = state + 'Text' - data.resetText || $el.data('resetText', $el[val]()) - - $el[val](data[state] || this.options[state]) - - // push to event loop to allow forms to submit - setTimeout(function () { - state == 'loadingText' ? - $el.addClass(d).attr(d, d) : - $el.removeClass(d).removeAttr(d) - }, 0) - } - - Button.prototype.toggle = function () { - var $parent = this.$element.closest('[data-toggle="buttons-radio"]') - - $parent && $parent - .find('.active') - .removeClass('active') - - this.$element.toggleClass('active') - } - - - /* BUTTON PLUGIN DEFINITION - * ======================== */ - - var old = $.fn.button - - $.fn.button = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('button') - , options = typeof option == 'object' && option - if (!data) $this.data('button', (data = new Button(this, options))) - if (option == 'toggle') data.toggle() - else if (option) data.setState(option) - }) - } - - $.fn.button.defaults = { - loadingText: 'loading...' - } - - $.fn.button.Constructor = Button - - - /* BUTTON NO CONFLICT - * ================== */ - - $.fn.button.noConflict = function () { - $.fn.button = old - return this - } - - - /* BUTTON DATA-API - * =============== */ - - $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - $btn.button('toggle') - }) - -}(window.jQuery);/* ========================================================== - * bootstrap-carousel.js v2.3.2 - * https://twitter.github.com/bootstrap/javascript.html#carousel - * ========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* CAROUSEL CLASS DEFINITION - * ========================= */ - - var Carousel = function (element, options) { - this.$element = $(element) - this.$indicators = this.$element.find('.carousel-indicators') - this.options = options - this.options.pause == 'hover' && this.$element - .on('mouseenter', $.proxy(this.pause, this)) - .on('mouseleave', $.proxy(this.cycle, this)) - } - - Carousel.prototype = { - - cycle: function (e) { - if (!e) this.paused = false - if (this.interval) clearInterval(this.interval); - this.options.interval - && !this.paused - && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) - return this - } - - , getActiveIndex: function () { - this.$active = this.$element.find('.item.active') - this.$items = this.$active.parent().children() - return this.$items.index(this.$active) - } - - , to: function (pos) { - var activeIndex = this.getActiveIndex() - , that = this - - if (pos > (this.$items.length - 1) || pos < 0) return - - if (this.sliding) { - return this.$element.one('slid', function () { - that.to(pos) - }) - } - - if (activeIndex == pos) { - return this.pause().cycle() - } - - return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) - } - - , pause: function (e) { - if (!e) this.paused = true - if (this.$element.find('.next, .prev').length && $.support.transition.end) { - this.$element.trigger($.support.transition.end) - this.cycle(true) - } - clearInterval(this.interval) - this.interval = null - return this - } - - , next: function () { - if (this.sliding) return - return this.slide('next') - } - - , prev: function () { - if (this.sliding) return - return this.slide('prev') - } - - , slide: function (type, next) { - var $active = this.$element.find('.item.active') - , $next = next || $active[type]() - , isCycling = this.interval - , direction = type == 'next' ? 'left' : 'right' - , fallback = type == 'next' ? 'first' : 'last' - , that = this - , e - - this.sliding = true - - isCycling && this.pause() - - $next = $next.length ? $next : this.$element.find('.item')[fallback]() - - e = $.Event('slide', { - relatedTarget: $next[0] - , direction: direction - }) - - if ($next.hasClass('active')) return - - if (this.$indicators.length) { - this.$indicators.find('.active').removeClass('active') - this.$element.one('slid', function () { - var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) - $nextIndicator && $nextIndicator.addClass('active') - }) - } - - if ($.support.transition && this.$element.hasClass('slide')) { - this.$element.trigger(e) - if (e.isDefaultPrevented()) return - $next.addClass(type) - $next[0].offsetWidth // force reflow - $active.addClass(direction) - $next.addClass(direction) - this.$element.one($.support.transition.end, function () { - $next.removeClass([type, direction].join(' ')).addClass('active') - $active.removeClass(['active', direction].join(' ')) - that.sliding = false - setTimeout(function () { that.$element.trigger('slid') }, 0) - }) - } else { - this.$element.trigger(e) - if (e.isDefaultPrevented()) return - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger('slid') - } - - isCycling && this.cycle() - - return this - } - - } - - - /* CAROUSEL PLUGIN DEFINITION - * ========================== */ - - var old = $.fn.carousel - - $.fn.carousel = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('carousel') - , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) - , action = typeof option == 'string' ? option : options.slide - if (!data) $this.data('carousel', (data = new Carousel(this, options))) - if (typeof option == 'number') data.to(option) - else if (action) data[action]() - else if (options.interval) data.pause().cycle() - }) - } - - $.fn.carousel.defaults = { - interval: 5000 - , pause: 'hover' - } - - $.fn.carousel.Constructor = Carousel - - - /* CAROUSEL NO CONFLICT - * ==================== */ - - $.fn.carousel.noConflict = function () { - $.fn.carousel = old - return this - } - - /* CAROUSEL DATA-API - * ================= */ - - $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { - var $this = $(this), href - , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 - , options = $.extend({}, $target.data(), $this.data()) - , slideIndex - - $target.carousel(options) - - if (slideIndex = $this.attr('data-slide-to')) { - $target.data('carousel').pause().to(slideIndex).cycle() - } - - e.preventDefault() - }) - -}(window.jQuery);/* ============================================================= - * bootstrap-collapse.js v2.3.2 - * https://twitter.github.com/bootstrap/javascript.html#collapse - * ============================================================= - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* COLLAPSE PUBLIC CLASS DEFINITION - * ================================ */ - - var Collapse = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, $.fn.collapse.defaults, options) - - if (this.options.parent) { - this.$parent = $(this.options.parent) - } - - this.options.toggle && this.toggle() - } - - Collapse.prototype = { - - constructor: Collapse - - , dimension: function () { - var hasWidth = this.$element.hasClass('width') - return hasWidth ? 'width' : 'height' - } - - , show: function () { - var dimension - , scroll - , actives - , hasData - - if (this.transitioning || this.$element.hasClass('in')) return - - dimension = this.dimension() - scroll = $.camelCase(['scroll', dimension].join('-')) - actives = this.$parent && this.$parent.find('> .accordion-group > .in') - - if (actives && actives.length) { - hasData = actives.data('collapse') - if (hasData && hasData.transitioning) return - actives.collapse('hide') - hasData || actives.data('collapse', null) - } - - this.$element[dimension](0) - this.transition('addClass', $.Event('show'), 'shown') - $.support.transition && this.$element[dimension](this.$element[0][scroll]) - } - - , hide: function () { - var dimension - if (this.transitioning || !this.$element.hasClass('in')) return - dimension = this.dimension() - this.reset(this.$element[dimension]()) - this.transition('removeClass', $.Event('hide'), 'hidden') - this.$element[dimension](0) - } - - , reset: function (size) { - var dimension = this.dimension() - - this.$element - .removeClass('collapse') - [dimension](size || 'auto') - [0].offsetWidth - - this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') - - return this - } - - , transition: function (method, startEvent, completeEvent) { - var that = this - , complete = function () { - if (startEvent.type == 'show') that.reset() - that.transitioning = 0 - that.$element.trigger(completeEvent) - } - - this.$element.trigger(startEvent) - - if (startEvent.isDefaultPrevented()) return - - this.transitioning = 1 - - this.$element[method]('in') - - $.support.transition && this.$element.hasClass('collapse') ? - this.$element.one($.support.transition.end, complete) : - complete() - } - - , toggle: function () { - this[this.$element.hasClass('in') ? 'hide' : 'show']() - } - - } - - - /* COLLAPSE PLUGIN DEFINITION - * ========================== */ - - var old = $.fn.collapse - - $.fn.collapse = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('collapse') - , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option) - if (!data) $this.data('collapse', (data = new Collapse(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.collapse.defaults = { - toggle: true - } - - $.fn.collapse.Constructor = Collapse - - - /* COLLAPSE NO CONFLICT - * ==================== */ - - $.fn.collapse.noConflict = function () { - $.fn.collapse = old - return this - } - - - /* COLLAPSE DATA-API - * ================= */ - - $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { - var $this = $(this), href - , target = $this.attr('data-target') - || e.preventDefault() - || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 - , option = $(target).data('collapse') ? 'toggle' : $this.data() - $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') - $(target).collapse(option) - }) - -}(window.jQuery);/* ============================================================ - * bootstrap-dropdown.js v2.3.2 - * https://twitter.github.com/bootstrap/javascript.html#dropdowns - * ============================================================ - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* DROPDOWN CLASS DEFINITION - * ========================= */ - - var toggle = '[data-toggle=dropdown]' - , Dropdown = function (element) { - var $el = $(element).on('click.dropdown.data-api', this.toggle) - $('html').on('click.dropdown.data-api', function () { - $el.parent().removeClass('open') - }) - } - - Dropdown.prototype = { - - constructor: Dropdown - - , toggle: function (e) { - var $this = $(this) - , $parent - , isActive - - if ($this.is('.disabled, :disabled')) return - - $parent = getParent($this) - - isActive = $parent.hasClass('open') - - clearMenus() - - if (!isActive) { - if ('ontouchstart' in document.documentElement) { - // if mobile we we use a backdrop because click events don't delegate - $('