├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── Securing_Microservices_OpenID_Connect_Spring_Security_5_1.pdf ├── docs ├── .gitignore ├── LICENSE ├── README.md ├── api-doc.html ├── bower.json ├── css │ ├── print │ │ ├── paper.css │ │ └── pdf.css │ ├── reset.css │ ├── reveal.css │ ├── reveal.scss │ └── theme │ │ ├── README.md │ │ ├── beige.css │ │ ├── black.css │ │ ├── blood.css │ │ ├── images │ │ ├── nt_logo_small.png │ │ └── spring_io_logo.png │ │ ├── league.css │ │ ├── moon.css │ │ ├── night.css │ │ ├── novatec.css │ │ ├── serif.css │ │ ├── simple.css │ │ ├── sky.css │ │ ├── solarized.css │ │ ├── source │ │ ├── beige.scss │ │ ├── black.scss │ │ ├── blood.scss │ │ ├── league.scss │ │ ├── moon.scss │ │ ├── night.scss │ │ ├── novatec.scss │ │ ├── serif.scss │ │ ├── simple.scss │ │ ├── sky.scss │ │ ├── solarized.scss │ │ ├── spring_io.scss │ │ └── white.scss │ │ ├── spring_io.css │ │ ├── template │ │ ├── mixins.scss │ │ ├── settings.scss │ │ └── theme.scss │ │ └── white.css ├── demo.html ├── gruntfile.js ├── images │ ├── OpenID_logo_2.svg.png │ ├── Valet_Ferrari.png │ ├── agile-security-book.jpg │ ├── andreas_falk.jpg │ ├── authorization_code_schema.png │ ├── authorization_code_schema.xml │ ├── automatic_role_mapping.png │ ├── cropped-novatec-favicon-192x192.png │ ├── cropped-novatec-favicon-32x32.png │ ├── demo-architecture.png │ ├── demo-architecture.xml │ ├── devops-handbook.jpg │ ├── devtools_cookies.png │ ├── implicit_schema.png │ ├── implicit_schema.xml │ ├── iron-glad-java.jpg │ ├── jwt_generator.png │ ├── jwt_generator_result.png │ ├── jwt_io.png │ ├── jwt_io_decoded.png │ ├── keycloak_logo.png │ ├── keycloak_session.png │ ├── keycloak_sessions.png │ ├── kubernetes_session.png │ ├── library_client.png │ ├── manico_tweet_oauth2_not_authentication.png │ ├── manico_xss_local_storage.jpeg │ ├── manual_role_mapping.png │ ├── novatec-back.png │ ├── novatec-logo.jpg │ ├── novatec-logo.png │ ├── novatec_logo_big.png │ ├── novatec_offices.png │ ├── oauth.png │ ├── oauth2_in_action.jpg │ ├── oauth2_protocol.png │ ├── oauth2_protocol.xml │ ├── oauth2_roles.png │ ├── oauth_implicit_grant_attacks_d_fett.png │ ├── oidc-map-2014.png │ ├── oidc_roles.png │ ├── openredirector_spring_security.png │ ├── osw2019picture.jpg │ ├── owasp-logo.png │ ├── security_session_grandja.png │ ├── server_web.png │ ├── server_web.xml │ ├── spa.png │ ├── spa.xml │ ├── spring-logo.png │ ├── spring_io_2019_workshop.jpg │ ├── spring_io_logo.png │ ├── spring_security_5_2.png │ ├── spring_security_new.png │ ├── spring_security_new.xml │ ├── spring_security_old.png │ ├── spring_security_old.xml │ ├── threat-modeling-book.jpg │ ├── title_image.png │ ├── token_validation.png │ ├── token_validation.xml │ └── why_not_use_implicit_grant.png ├── index.html ├── js │ └── reveal.js ├── lib │ ├── css │ │ ├── monokai.css │ │ └── zenburn.css │ ├── font │ │ ├── league-gothic │ │ │ ├── LICENSE │ │ │ ├── league-gothic.css │ │ │ ├── league-gothic.eot │ │ │ ├── league-gothic.ttf │ │ │ └── league-gothic.woff │ │ └── source-sans-pro │ │ │ ├── LICENSE │ │ │ ├── source-sans-pro-italic.eot │ │ │ ├── source-sans-pro-italic.ttf │ │ │ ├── source-sans-pro-italic.woff │ │ │ ├── source-sans-pro-regular.eot │ │ │ ├── source-sans-pro-regular.ttf │ │ │ ├── source-sans-pro-regular.woff │ │ │ ├── source-sans-pro-semibold.eot │ │ │ ├── source-sans-pro-semibold.ttf │ │ │ ├── source-sans-pro-semibold.woff │ │ │ ├── source-sans-pro-semibolditalic.eot │ │ │ ├── source-sans-pro-semibolditalic.ttf │ │ │ ├── source-sans-pro-semibolditalic.woff │ │ │ └── source-sans-pro.css │ └── js │ │ ├── html5shiv.js │ │ └── promise.js ├── package.json └── plugin │ ├── elapsed-time-bar │ └── elapsed-time-bar.js │ ├── highlight │ └── highlight.js │ ├── markdown │ ├── example.html │ ├── example.md │ ├── markdown.js │ └── marked.js │ ├── math │ └── math.js │ ├── multiplex │ ├── client.js │ ├── index.js │ ├── master.js │ └── package.json │ ├── notes-server │ ├── client.js │ ├── index.js │ └── notes.html │ ├── notes │ ├── notes.html │ └── notes.js │ ├── print-pdf │ └── print-pdf.js │ ├── search │ └── search.js │ ├── tagcloud │ └── tagcloud.js │ └── zoom-js │ └── zoom.js ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── intro-labs ├── README.md ├── auth-code-demo │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── authorizationcode │ │ │ └── client │ │ │ ├── AuthorizationCodeDemo.java │ │ │ ├── config │ │ │ └── WebClientConfiguration.java │ │ │ ├── jwt │ │ │ └── JsonWebToken.java │ │ │ └── web │ │ │ ├── AuthorizationRequestController.java │ │ │ ├── CodeCallbackController.java │ │ │ ├── TokenIntrospectionController.java │ │ │ ├── TokenRequest.java │ │ │ ├── TokenRequestController.java │ │ │ └── TokenResponse.java │ │ └── resources │ │ ├── application.yml │ │ ├── static │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ └── js │ │ │ ├── bootstrap.bundle.js │ │ │ ├── bootstrap.bundle.js.map │ │ │ ├── bootstrap.bundle.min.js │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.js.map │ │ │ ├── bootstrap.min.js │ │ │ ├── bootstrap.min.js.map │ │ │ ├── jquery.min.js │ │ │ └── popper.min.js │ │ └── templates │ │ ├── access-token.html │ │ ├── authcode.html │ │ ├── error.html │ │ ├── init-auth-request.html │ │ └── introspection.html └── github-client │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ └── main │ ├── java │ └── com │ │ └── example │ │ └── github │ │ ├── GitHubClientApplication.java │ │ ├── config │ │ └── WebClientConfiguration.java │ │ └── restapi │ │ ├── GitHubNotification.java │ │ ├── GitHubNotificationsController.java │ │ ├── GitHubRepository.java │ │ ├── GitHubSubject.java │ │ └── UserIdController.java │ └── resources │ ├── application.yml │ └── templates │ ├── index.html │ └── notifications.html ├── lab1 ├── README.md ├── library-server-complete-automatic │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ │ ├── docs │ │ └── asciidoc │ │ │ └── index.adoc │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── library │ │ │ │ └── server │ │ │ │ ├── CompleteAutomaticLibraryServerApplication.java │ │ │ │ ├── DataInitializer.java │ │ │ │ ├── api │ │ │ │ ├── BookRestController.java │ │ │ │ ├── ErrorHandler.java │ │ │ │ ├── UserRestController.java │ │ │ │ └── resource │ │ │ │ │ ├── BookListResource.java │ │ │ │ │ ├── BookResource.java │ │ │ │ │ ├── ModifyingUserResource.java │ │ │ │ │ ├── UserListResource.java │ │ │ │ │ ├── UserResource.java │ │ │ │ │ └── assembler │ │ │ │ │ ├── BookListResourceAssembler.java │ │ │ │ │ ├── BookResourceAssembler.java │ │ │ │ │ └── UserResourceAssembler.java │ │ │ │ ├── business │ │ │ │ ├── BookService.java │ │ │ │ └── UserService.java │ │ │ │ ├── common │ │ │ │ └── Role.java │ │ │ │ ├── config │ │ │ │ ├── IdGeneratorConfiguration.java │ │ │ │ └── WebSecurityConfiguration.java │ │ │ │ ├── dataaccess │ │ │ │ ├── Book.java │ │ │ │ ├── BookRepository.java │ │ │ │ ├── User.java │ │ │ │ └── UserRepository.java │ │ │ │ └── security │ │ │ │ ├── LibraryUser.java │ │ │ │ ├── LibraryUserDetailsService.java │ │ │ │ └── PreAuthorizeNotRequired.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── library │ │ └── server │ │ ├── api │ │ ├── BookApiIntegrationTests.java │ │ └── UserApiIntegrationTests.java │ │ ├── business │ │ ├── BookServiceAuthorizationTest.java │ │ └── UserServiceAuthorizationTest.java │ │ ├── dataaccess │ │ ├── BookBuilder.java │ │ └── UserBuilder.java │ │ └── test │ │ ├── WithMockJwt.java │ │ └── WithMockJwtSecurityContextFactory.java ├── library-server-complete-custom │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ │ ├── docs │ │ └── asciidoc │ │ │ └── index.adoc │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── library │ │ │ │ └── server │ │ │ │ ├── CompleteCustomLibraryServerApplication.java │ │ │ │ ├── DataInitializer.java │ │ │ │ ├── api │ │ │ │ ├── BookRestController.java │ │ │ │ ├── ErrorHandler.java │ │ │ │ ├── UserRestController.java │ │ │ │ └── resource │ │ │ │ │ ├── BookListResource.java │ │ │ │ │ ├── BookResource.java │ │ │ │ │ ├── ModifyingUserResource.java │ │ │ │ │ ├── UserListResource.java │ │ │ │ │ ├── UserResource.java │ │ │ │ │ └── assembler │ │ │ │ │ ├── BookListResourceAssembler.java │ │ │ │ │ ├── BookResourceAssembler.java │ │ │ │ │ └── UserResourceAssembler.java │ │ │ │ ├── business │ │ │ │ ├── BookService.java │ │ │ │ └── UserService.java │ │ │ │ ├── common │ │ │ │ └── Role.java │ │ │ │ ├── config │ │ │ │ ├── IdGeneratorConfiguration.java │ │ │ │ └── WebSecurityConfiguration.java │ │ │ │ ├── dataaccess │ │ │ │ ├── Book.java │ │ │ │ ├── BookRepository.java │ │ │ │ ├── User.java │ │ │ │ └── UserRepository.java │ │ │ │ └── security │ │ │ │ ├── AudienceValidator.java │ │ │ │ ├── LibraryUser.java │ │ │ │ ├── LibraryUserDetailsService.java │ │ │ │ ├── LibraryUserJwtAuthenticationConverter.java │ │ │ │ ├── LibraryUserRolesJwtAuthenticationConverter.java │ │ │ │ └── PreAuthorizeNotRequired.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── library │ │ └── server │ │ ├── api │ │ ├── BookApiIntegrationTests.java │ │ └── UserApiIntegrationTests.java │ │ ├── business │ │ ├── BookServiceAuthorizationTest.java │ │ └── UserServiceAuthorizationTest.java │ │ ├── dataaccess │ │ ├── BookBuilder.java │ │ └── UserBuilder.java │ │ └── test │ │ ├── WithMockLibraryUser.java │ │ └── WithMockLibraryUserSecurityContextFactory.java └── library-server-initial │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ ├── docs │ └── asciidoc │ │ └── index.adoc │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── library │ │ │ └── server │ │ │ ├── DataInitializer.java │ │ │ ├── Lab1InitialLibraryServerApplication.java │ │ │ ├── api │ │ │ ├── BookRestController.java │ │ │ ├── ErrorHandler.java │ │ │ ├── UserRestController.java │ │ │ └── resource │ │ │ │ ├── BookListResource.java │ │ │ │ ├── BookResource.java │ │ │ │ ├── ModifyingUserResource.java │ │ │ │ ├── UserListResource.java │ │ │ │ ├── UserResource.java │ │ │ │ └── assembler │ │ │ │ ├── BookListResourceAssembler.java │ │ │ │ ├── BookResourceAssembler.java │ │ │ │ └── UserResourceAssembler.java │ │ │ ├── business │ │ │ ├── BookService.java │ │ │ └── UserService.java │ │ │ ├── common │ │ │ └── Role.java │ │ │ ├── config │ │ │ ├── IdGeneratorConfiguration.java │ │ │ └── WebSecurityConfiguration.java │ │ │ ├── dataaccess │ │ │ ├── Book.java │ │ │ ├── BookRepository.java │ │ │ ├── User.java │ │ │ └── UserRepository.java │ │ │ └── security │ │ │ ├── LibraryUser.java │ │ │ ├── LibraryUserDetailsService.java │ │ │ └── PreAuthorizeNotRequired.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── example │ └── library │ └── server │ ├── api │ ├── BookApiIntegrationTests.java │ └── UserApiIntegrationTests.java │ ├── business │ ├── BookServiceAuthorizationTest.java │ └── UserServiceAuthorizationTest.java │ ├── dataaccess │ ├── BookBuilder.java │ └── UserBuilder.java │ └── test │ ├── WithMockLibraryUser.java │ └── WithMockLibraryUserSecurityContextFactory.java ├── lab2 ├── README.md ├── library-client-complete │ ├── .gitignore │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── library │ │ │ │ └── client │ │ │ │ ├── LibraryClientCompleteApplication.java │ │ │ │ ├── config │ │ │ │ ├── WebClientConfiguration.java │ │ │ │ └── WebSecurityConfiguration.java │ │ │ │ └── web │ │ │ │ ├── BookListResource.java │ │ │ │ ├── BookResource.java │ │ │ │ ├── BooksController.java │ │ │ │ ├── CreateBookResource.java │ │ │ │ ├── ErrorHandler.java │ │ │ │ └── User.java │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-grid.css.map │ │ │ │ ├── bootstrap-grid.min.css │ │ │ │ ├── bootstrap-grid.min.css.map │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap-reboot.css.map │ │ │ │ ├── bootstrap-reboot.min.css │ │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── bootstrap.min.css.map │ │ │ └── js │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ ├── bootstrap.bundle.js.map │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.js.map │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── bootstrap.min.js.map │ │ │ │ ├── jquery.min.js │ │ │ │ └── popper.min.js │ │ │ └── templates │ │ │ ├── createbookform.html │ │ │ ├── error.html │ │ │ └── index.html │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── library │ │ └── client │ │ └── LibraryClientCompleteApplicationTests.java └── library-client-initial │ ├── .gitignore │ ├── build.gradle │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── library │ │ │ └── client │ │ │ ├── LibraryClientInitialApplication.java │ │ │ ├── config │ │ │ ├── WebClientConfiguration.java │ │ │ └── WebSecurityConfiguration.java │ │ │ └── web │ │ │ ├── BookListResource.java │ │ │ ├── BookResource.java │ │ │ ├── BooksController.java │ │ │ ├── CreateBookResource.java │ │ │ ├── ErrorHandler.java │ │ │ └── User.java │ └── resources │ │ ├── application.yml │ │ ├── static │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ └── js │ │ │ ├── bootstrap.bundle.js │ │ │ ├── bootstrap.bundle.js.map │ │ │ ├── bootstrap.bundle.min.js │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.js.map │ │ │ ├── bootstrap.min.js │ │ │ ├── bootstrap.min.js.map │ │ │ ├── jquery.min.js │ │ │ └── popper.min.js │ │ └── templates │ │ ├── createbookform.html │ │ ├── error.html │ │ └── index.html │ └── test │ └── java │ └── com │ └── example │ └── library │ └── client │ └── LibraryClientInitialApplicationTests.java ├── lab3 ├── README.md ├── library-client-credentials-complete │ ├── .gitignore │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── library │ │ │ │ └── client │ │ │ │ └── credentials │ │ │ │ ├── LibraryClientCredentialsCompleteApplication.java │ │ │ │ ├── config │ │ │ │ ├── WebClientConfiguration.java │ │ │ │ └── WebSecurityConfig.java │ │ │ │ └── web │ │ │ │ ├── BookListResource.java │ │ │ │ ├── BookResource.java │ │ │ │ ├── BooksController.java │ │ │ │ ├── ErrorHandler.java │ │ │ │ └── User.java │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-grid.css.map │ │ │ │ ├── bootstrap-grid.min.css │ │ │ │ ├── bootstrap-grid.min.css.map │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap-reboot.css.map │ │ │ │ ├── bootstrap-reboot.min.css │ │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── bootstrap.min.css.map │ │ │ └── js │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ ├── bootstrap.bundle.js.map │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.js.map │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── bootstrap.min.js.map │ │ │ │ ├── jquery.min.js │ │ │ │ └── popper.min.js │ │ │ └── templates │ │ │ ├── error.html │ │ │ └── index.html │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── library │ │ └── client │ │ └── credentials │ │ └── LibraryClientCredentialsCompleteApplicationTests.java └── library-client-credentials-initial │ ├── .gitignore │ ├── build.gradle │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── library │ │ │ └── client │ │ │ └── credentials │ │ │ ├── LibraryClientCredentialsInitialApplication.java │ │ │ ├── config │ │ │ ├── WebClientConfiguration.java │ │ │ └── WebSecurityConfig.java │ │ │ └── web │ │ │ ├── BookListResource.java │ │ │ ├── BookResource.java │ │ │ ├── BooksController.java │ │ │ ├── ErrorHandler.java │ │ │ └── User.java │ └── resources │ │ ├── application.yml │ │ ├── static │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ └── js │ │ │ ├── bootstrap.bundle.js │ │ │ ├── bootstrap.bundle.js.map │ │ │ ├── bootstrap.bundle.min.js │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.js.map │ │ │ ├── bootstrap.min.js │ │ │ ├── bootstrap.min.js.map │ │ │ ├── jquery.min.js │ │ │ └── popper.min.js │ │ └── templates │ │ ├── error.html │ │ └── index.html │ └── test │ └── java │ └── com │ └── example │ └── library │ └── client │ └── credentials │ └── LibraryClientCredentialsInitialApplicationTests.java ├── lab4 ├── README.md ├── jwt-generator │ ├── .gitignore │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── jwt │ │ │ │ └── generator │ │ │ │ ├── JwtController.java │ │ │ │ ├── JwtGeneratorApplication.java │ │ │ │ └── User.java │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── jwt_keys.jks │ │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-grid.css.map │ │ │ │ ├── bootstrap-grid.min.css │ │ │ │ ├── bootstrap-grid.min.css.map │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap-reboot.css.map │ │ │ │ ├── bootstrap-reboot.min.css │ │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── bootstrap.min.css.map │ │ │ └── js │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ ├── bootstrap.bundle.js.map │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.js.map │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── bootstrap.min.js.map │ │ │ │ ├── jquery.min.js │ │ │ │ └── popper.min.js │ │ │ └── templates │ │ │ ├── jwt-form.html │ │ │ └── result.html │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── jwt │ │ └── generator │ │ └── JwtGeneratorApplicationTests.java └── library-server-static-complete │ ├── .gitignore │ ├── build.gradle │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ ├── docs │ └── asciidoc │ │ └── index.adoc │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── library │ │ │ └── server │ │ │ ├── CompleteStaticLibraryServerApplication.java │ │ │ ├── DataInitializer.java │ │ │ ├── api │ │ │ ├── BookRestController.java │ │ │ ├── ErrorHandler.java │ │ │ ├── UserRestController.java │ │ │ └── resource │ │ │ │ ├── BookListResource.java │ │ │ │ ├── BookResource.java │ │ │ │ ├── ModifyingUserResource.java │ │ │ │ ├── UserListResource.java │ │ │ │ └── UserResource.java │ │ │ ├── business │ │ │ ├── BookService.java │ │ │ └── UserService.java │ │ │ ├── common │ │ │ └── Role.java │ │ │ ├── config │ │ │ ├── IdGeneratorConfiguration.java │ │ │ └── WebSecurityConfiguration.java │ │ │ ├── dataaccess │ │ │ ├── Book.java │ │ │ ├── BookRepository.java │ │ │ ├── User.java │ │ │ └── UserRepository.java │ │ │ └── security │ │ │ ├── AudienceValidator.java │ │ │ ├── LibraryUser.java │ │ │ ├── LibraryUserDetailsService.java │ │ │ ├── LibraryUserJwtAuthenticationConverter.java │ │ │ ├── LibraryUserRolesJwtAuthenticationConverter.java │ │ │ └── PreAuthorizeNotRequired.java │ └── resources │ │ ├── application.yml │ │ └── library_server.pub │ └── test │ └── java │ └── com │ └── example │ └── library │ └── server │ ├── api │ ├── BookApiIntegrationTests.java │ └── UserApiIntegrationTests.java │ └── dataaccess │ ├── BookBuilder.java │ └── UserBuilder.java ├── settings.gradle └── setup_keycloak ├── README.md ├── init_keycloak.sh ├── keycloak_data.zip └── keycloak_workshop.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.war 15 | *.nar 16 | *.ear 17 | *.tar.gz 18 | *.rar 19 | 20 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 21 | hs_err_pid* 22 | 23 | # vs code 24 | .vscode/ 25 | .idea/ 26 | .gradle/ 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | dist: trusty 3 | install: skip 4 | sudo: required 5 | services: 6 | - docker 7 | 8 | jobs: 9 | include: 10 | 11 | - stage: build 12 | jdk: openjdk8 13 | script: 14 | - ./gradlew build 15 | - stage: build 16 | jdk: oraclejdk9 17 | script: 18 | - ./gradlew build 19 | - stage: build 20 | jdk: openjdk11 21 | script: 22 | - ./gradlew build -------------------------------------------------------------------------------- /Securing_Microservices_OpenID_Connect_Spring_Security_5_1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/Securing_Microservices_OpenID_Connect_Spring_Security_5_1.pdf -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | *.iws 4 | *.eml 5 | out/ 6 | .DS_Store 7 | .svn 8 | log/*.log 9 | tmp/** 10 | node_modules/ 11 | .sass-cache 12 | css/reveal.min.css 13 | js/reveal.min.js 14 | package-lock.json 15 | -------------------------------------------------------------------------------- /docs/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2019 Hakim El Hattab, http://hakim.se, and reveal.js contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Spring I/O 2019 2 | 3 | [Presentation Slides (HTML5)](https://andifalk.github.io/oidc-workshop-spring-io-2019/) -------------------------------------------------------------------------------- /docs/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reveal.js", 3 | "version": "3.8.0", 4 | "main": [ 5 | "js/reveal.js", 6 | "css/reveal.css" 7 | ], 8 | "homepage": "http://revealjs.com", 9 | "license": "MIT", 10 | "description": "The HTML Presentation Framework", 11 | "authors": [ 12 | "Hakim El Hattab " 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "git://github.com/hakimel/reveal.js.git" 17 | }, 18 | "ignore": [ 19 | "**/.*", 20 | "node_modules", 21 | "bower_components", 22 | "test" 23 | ] 24 | } -------------------------------------------------------------------------------- /docs/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v4.0 | 20180602 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | main, menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, main, menu, nav, section { 29 | display: block; 30 | } -------------------------------------------------------------------------------- /docs/css/theme/README.md: -------------------------------------------------------------------------------- 1 | ## Dependencies 2 | 3 | Themes are written using Sass to keep things modular and reduce the need for repeated selectors across files. Make sure that you have the reveal.js development environment including the Grunt dependencies installed before proceeding: https://github.com/hakimel/reveal.js#full-setup 4 | 5 | ## Creating a Theme 6 | 7 | To create your own theme, start by duplicating a ```.scss``` file in [/css/theme/source](https://github.com/hakimel/reveal.js/blob/master/css/theme/source). It will be automatically compiled by Grunt from Sass to CSS (see the [Gruntfile](https://github.com/hakimel/reveal.js/blob/master/Gruntfile.js)) when you run `npm run build -- css-themes`. 8 | 9 | Each theme file does four things in the following order: 10 | 11 | 1. **Include [/css/theme/template/mixins.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/mixins.scss)** 12 | Shared utility functions. 13 | 14 | 2. **Include [/css/theme/template/settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss)** 15 | Declares a set of custom variables that the template file (step 4) expects. Can be overridden in step 3. 16 | 17 | 3. **Override** 18 | This is where you override the default theme. Either by specifying variables (see [settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss) for reference) or by adding any selectors and styles you please. 19 | 20 | 4. **Include [/css/theme/template/theme.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/theme.scss)** 21 | The template theme file which will generate final CSS output based on the currently defined variables. 22 | -------------------------------------------------------------------------------- /docs/css/theme/images/nt_logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/css/theme/images/nt_logo_small.png -------------------------------------------------------------------------------- /docs/css/theme/images/spring_io_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/css/theme/images/spring_io_logo.png -------------------------------------------------------------------------------- /docs/css/theme/source/beige.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Beige theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | 15 | // Include theme-specific fonts 16 | @import url(../../lib/font/league-gothic/league-gothic.css); 17 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 18 | 19 | 20 | // Override theme settings (see ../template/settings.scss) 21 | $mainColor: #333; 22 | $headingColor: #333; 23 | $headingTextShadow: none; 24 | $backgroundColor: #f7f3de; 25 | $linkColor: #8b743d; 26 | $linkColorHover: lighten( $linkColor, 20% ); 27 | $selectionBackgroundColor: rgba(79, 64, 28, 0.99); 28 | $heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); 29 | 30 | // Background generator 31 | @mixin bodyBackground() { 32 | @include radial-gradient( rgba(247,242,211,1), rgba(255,255,255,1) ); 33 | } 34 | 35 | 36 | 37 | // Theme template ------------------------------ 38 | @import "../template/theme"; 39 | // --------------------------------------------- -------------------------------------------------------------------------------- /docs/css/theme/source/black.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Black theme for reveal.js. This is the opposite of the 'white' theme. 3 | * 4 | * By Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/source-sans-pro/source-sans-pro.css); 16 | 17 | 18 | // Override theme settings (see ../template/settings.scss) 19 | $backgroundColor: #191919; 20 | 21 | $mainColor: #fff; 22 | $headingColor: #fff; 23 | 24 | $mainFontSize: 42px; 25 | $mainFont: 'Source Sans Pro', Helvetica, sans-serif; 26 | $headingFont: 'Source Sans Pro', Helvetica, sans-serif; 27 | $headingTextShadow: none; 28 | $headingLetterSpacing: normal; 29 | $headingTextTransform: uppercase; 30 | $headingFontWeight: 600; 31 | $linkColor: #42affa; 32 | $linkColorHover: lighten( $linkColor, 15% ); 33 | $selectionBackgroundColor: lighten( $linkColor, 25% ); 34 | 35 | $heading1Size: 2.5em; 36 | $heading2Size: 1.6em; 37 | $heading3Size: 1.3em; 38 | $heading4Size: 1.0em; 39 | 40 | section.has-light-background { 41 | &, h1, h2, h3, h4, h5, h6 { 42 | color: #222; 43 | } 44 | } 45 | 46 | 47 | // Theme template ------------------------------ 48 | @import "../template/theme"; 49 | // --------------------------------------------- -------------------------------------------------------------------------------- /docs/css/theme/source/league.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * League theme for reveal.js. 3 | * 4 | * This was the default theme pre-3.0.0. 5 | * 6 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 7 | */ 8 | 9 | 10 | // Default mixins and settings ----------------- 11 | @import "../template/mixins"; 12 | @import "../template/settings"; 13 | // --------------------------------------------- 14 | 15 | 16 | 17 | // Include theme-specific fonts 18 | @import url(../../lib/font/league-gothic/league-gothic.css); 19 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 20 | 21 | // Override theme settings (see ../template/settings.scss) 22 | $headingTextShadow: 0px 0px 6px rgba(0,0,0,0.2); 23 | $heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); 24 | 25 | // Background generator 26 | @mixin bodyBackground() { 27 | @include radial-gradient( rgba(28,30,32,1), rgba(85,90,95,1) ); 28 | } 29 | 30 | 31 | 32 | // Theme template ------------------------------ 33 | @import "../template/theme"; 34 | // --------------------------------------------- -------------------------------------------------------------------------------- /docs/css/theme/source/moon.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Solarized Dark theme for reveal.js. 3 | * Author: Achim Staebler 4 | */ 5 | 6 | 7 | // Default mixins and settings ----------------- 8 | @import "../template/mixins"; 9 | @import "../template/settings"; 10 | // --------------------------------------------- 11 | 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/league-gothic/league-gothic.css); 16 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 17 | 18 | /** 19 | * Solarized colors by Ethan Schoonover 20 | */ 21 | html * { 22 | color-profile: sRGB; 23 | rendering-intent: auto; 24 | } 25 | 26 | // Solarized colors 27 | $base03: #002b36; 28 | $base02: #073642; 29 | $base01: #586e75; 30 | $base00: #657b83; 31 | $base0: #839496; 32 | $base1: #93a1a1; 33 | $base2: #eee8d5; 34 | $base3: #fdf6e3; 35 | $yellow: #b58900; 36 | $orange: #cb4b16; 37 | $red: #dc322f; 38 | $magenta: #d33682; 39 | $violet: #6c71c4; 40 | $blue: #268bd2; 41 | $cyan: #2aa198; 42 | $green: #859900; 43 | 44 | // Override theme settings (see ../template/settings.scss) 45 | $mainColor: $base1; 46 | $headingColor: $base2; 47 | $headingTextShadow: none; 48 | $backgroundColor: $base03; 49 | $linkColor: $blue; 50 | $linkColorHover: lighten( $linkColor, 20% ); 51 | $selectionBackgroundColor: $magenta; 52 | 53 | 54 | 55 | // Theme template ------------------------------ 56 | @import "../template/theme"; 57 | // --------------------------------------------- 58 | -------------------------------------------------------------------------------- /docs/css/theme/source/night.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Black theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(https://fonts.googleapis.com/css?family=Montserrat:700); 16 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic); 17 | 18 | 19 | // Override theme settings (see ../template/settings.scss) 20 | $backgroundColor: #111; 21 | 22 | $mainFont: 'Open Sans', sans-serif; 23 | $linkColor: #e7ad52; 24 | $linkColorHover: lighten( $linkColor, 20% ); 25 | $headingFont: 'Montserrat', Impact, sans-serif; 26 | $headingTextShadow: none; 27 | $headingLetterSpacing: -0.03em; 28 | $headingTextTransform: none; 29 | $selectionBackgroundColor: #e7ad52; 30 | 31 | 32 | // Theme template ------------------------------ 33 | @import "../template/theme"; 34 | // --------------------------------------------- -------------------------------------------------------------------------------- /docs/css/theme/source/novatec.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Solarized Dark theme for reveal.js. 3 | * Author: Achim Staebler 4 | */ 5 | 6 | 7 | // Default mixins and settings ----------------- 8 | @import "../template/mixins"; 9 | @import "../template/settings"; 10 | // --------------------------------------------- 11 | 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/league-gothic/league-gothic.css); 16 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 17 | 18 | /** 19 | * Solarized colors by Ethan Schoonover 20 | */ 21 | html * { 22 | color-profile: sRGB; 23 | rendering-intent: auto; 24 | } 25 | 26 | // Solarized colors 27 | $base03: #002b36; 28 | $base02: #073642; 29 | $base01: #586e75; 30 | $base00: #657b83; 31 | $base0: #839496; 32 | $base1: #93a1a1; 33 | $base2: #eee8d5; 34 | $base3: #fdf6e3; 35 | $yellow: #b58900; 36 | $orange: #cb4b16; 37 | $red: #dc322f; 38 | $magenta: #d33682; 39 | $violet: #6c71c4; 40 | $blue: #268bd2; 41 | $cyan: #2aa198; 42 | $green: #859900; 43 | 44 | // Override theme settings (see ../template/settings.scss) 45 | $mainColor: $base1; 46 | $headingColor: $base2; 47 | $headingTextShadow: none; 48 | $backgroundColor: $base03; 49 | $linkColor: $blue; 50 | $linkColorHover: lighten( $linkColor, 20% ); 51 | $selectionBackgroundColor: $magenta; 52 | 53 | 54 | 55 | // Theme template ------------------------------ 56 | @import "../template/theme"; 57 | // --------------------------------------------- 58 | -------------------------------------------------------------------------------- /docs/css/theme/source/serif.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * A simple theme for reveal.js presentations, similar 3 | * to the default theme. The accent color is brown. 4 | * 5 | * This theme is Copyright (C) 2012-2013 Owen Versteeg, http://owenversteeg.com - it is MIT licensed. 6 | */ 7 | 8 | 9 | // Default mixins and settings ----------------- 10 | @import "../template/mixins"; 11 | @import "../template/settings"; 12 | // --------------------------------------------- 13 | 14 | 15 | 16 | // Override theme settings (see ../template/settings.scss) 17 | $mainFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 18 | $mainColor: #000; 19 | $headingFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 20 | $headingColor: #383D3D; 21 | $headingTextShadow: none; 22 | $headingTextTransform: none; 23 | $backgroundColor: #F0F1EB; 24 | $linkColor: #51483D; 25 | $linkColorHover: lighten( $linkColor, 20% ); 26 | $selectionBackgroundColor: #26351C; 27 | 28 | .reveal a { 29 | line-height: 1.3em; 30 | } 31 | 32 | 33 | // Theme template ------------------------------ 34 | @import "../template/theme"; 35 | // --------------------------------------------- 36 | -------------------------------------------------------------------------------- /docs/css/theme/source/simple.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * A simple theme for reveal.js presentations, similar 3 | * to the default theme. The accent color is darkblue. 4 | * 5 | * This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed. 6 | * reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 7 | */ 8 | 9 | 10 | // Default mixins and settings ----------------- 11 | @import "../template/mixins"; 12 | @import "../template/settings"; 13 | // --------------------------------------------- 14 | 15 | 16 | 17 | // Include theme-specific fonts 18 | @import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700); 19 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 20 | 21 | 22 | // Override theme settings (see ../template/settings.scss) 23 | $mainFont: 'Lato', sans-serif; 24 | $mainColor: #000; 25 | $headingFont: 'News Cycle', Impact, sans-serif; 26 | $headingColor: #000; 27 | $headingTextShadow: none; 28 | $headingTextTransform: none; 29 | $backgroundColor: #fff; 30 | $linkColor: #00008B; 31 | $linkColorHover: lighten( $linkColor, 20% ); 32 | $selectionBackgroundColor: rgba(0, 0, 0, 0.99); 33 | 34 | section.has-dark-background { 35 | &, h1, h2, h3, h4, h5, h6 { 36 | color: #fff; 37 | } 38 | } 39 | 40 | 41 | // Theme template ------------------------------ 42 | @import "../template/theme"; 43 | // --------------------------------------------- -------------------------------------------------------------------------------- /docs/css/theme/source/sky.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Sky theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | 15 | // Include theme-specific fonts 16 | @import url(https://fonts.googleapis.com/css?family=Quicksand:400,700,400italic,700italic); 17 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700); 18 | 19 | 20 | // Override theme settings (see ../template/settings.scss) 21 | $mainFont: 'Open Sans', sans-serif; 22 | $mainColor: #333; 23 | $headingFont: 'Quicksand', sans-serif; 24 | $headingColor: #333; 25 | $headingLetterSpacing: -0.08em; 26 | $headingTextShadow: none; 27 | $backgroundColor: #f7fbfc; 28 | $linkColor: #3b759e; 29 | $linkColorHover: lighten( $linkColor, 20% ); 30 | $selectionBackgroundColor: #134674; 31 | 32 | // Fix links so they are not cut off 33 | .reveal a { 34 | line-height: 1.3em; 35 | } 36 | 37 | // Background generator 38 | @mixin bodyBackground() { 39 | @include radial-gradient( #add9e4, #f7fbfc ); 40 | } 41 | 42 | 43 | 44 | // Theme template ------------------------------ 45 | @import "../template/theme"; 46 | // --------------------------------------------- 47 | -------------------------------------------------------------------------------- /docs/css/theme/source/solarized.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Solarized Light theme for reveal.js. 3 | * Author: Achim Staebler 4 | */ 5 | 6 | 7 | // Default mixins and settings ----------------- 8 | @import "../template/mixins"; 9 | @import "../template/settings"; 10 | // --------------------------------------------- 11 | 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/league-gothic/league-gothic.css); 16 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 17 | 18 | 19 | /** 20 | * Solarized colors by Ethan Schoonover 21 | */ 22 | html * { 23 | color-profile: sRGB; 24 | rendering-intent: auto; 25 | } 26 | 27 | // Solarized colors 28 | $base03: #002b36; 29 | $base02: #073642; 30 | $base01: #586e75; 31 | $base00: #657b83; 32 | $base0: #839496; 33 | $base1: #93a1a1; 34 | $base2: #eee8d5; 35 | $base3: #fdf6e3; 36 | $yellow: #b58900; 37 | $orange: #cb4b16; 38 | $red: #dc322f; 39 | $magenta: #d33682; 40 | $violet: #6c71c4; 41 | $blue: #268bd2; 42 | $cyan: #2aa198; 43 | $green: #859900; 44 | 45 | // Override theme settings (see ../template/settings.scss) 46 | $mainColor: $base00; 47 | $headingColor: $base01; 48 | $headingTextShadow: none; 49 | $backgroundColor: $base3; 50 | $linkColor: $blue; 51 | $linkColorHover: lighten( $linkColor, 20% ); 52 | $selectionBackgroundColor: $magenta; 53 | 54 | // Background generator 55 | // @mixin bodyBackground() { 56 | // @include radial-gradient( rgba($base3,1), rgba(lighten($base3, 20%),1) ); 57 | // } 58 | 59 | 60 | 61 | // Theme template ------------------------------ 62 | @import "../template/theme"; 63 | // --------------------------------------------- 64 | -------------------------------------------------------------------------------- /docs/css/theme/source/spring_io.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Solarized Dark theme for reveal.js. 3 | * Author: Achim Staebler 4 | */ 5 | 6 | 7 | // Default mixins and settings ----------------- 8 | @import "../template/mixins"; 9 | @import "../template/settings"; 10 | // --------------------------------------------- 11 | 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/league-gothic/league-gothic.css); 16 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 17 | 18 | /** 19 | * Solarized colors by Ethan Schoonover 20 | */ 21 | html * { 22 | color-profile: sRGB; 23 | rendering-intent: auto; 24 | } 25 | 26 | // Solarized colors 27 | $base03: #002b36; 28 | $base02: #073642; 29 | $base01: #586e75; 30 | $base00: #657b83; 31 | $base0: #839496; 32 | $base1: #93a1a1; 33 | $base2: #eee8d5; 34 | $base3: #fdf6e3; 35 | $yellow: #b58900; 36 | $orange: #cb4b16; 37 | $red: #dc322f; 38 | $magenta: #d33682; 39 | $violet: #6c71c4; 40 | $blue: #268bd2; 41 | $cyan: #2aa198; 42 | $green: #859900; 43 | 44 | // Override theme settings (see ../template/settings.scss) 45 | $mainColor: $base1; 46 | $headingColor: $base2; 47 | $headingTextShadow: none; 48 | $backgroundColor: $base03; 49 | $linkColor: $blue; 50 | $linkColorHover: lighten( $linkColor, 20% ); 51 | $selectionBackgroundColor: $magenta; 52 | 53 | 54 | 55 | // Theme template ------------------------------ 56 | @import "../template/theme"; 57 | // --------------------------------------------- 58 | -------------------------------------------------------------------------------- /docs/css/theme/source/white.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * White theme for reveal.js. This is the opposite of the 'black' theme. 3 | * 4 | * By Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/source-sans-pro/source-sans-pro.css); 16 | 17 | 18 | // Override theme settings (see ../template/settings.scss) 19 | $backgroundColor: #fff; 20 | 21 | $mainColor: #222; 22 | $headingColor: #222; 23 | 24 | $mainFontSize: 42px; 25 | $mainFont: 'Source Sans Pro', Helvetica, sans-serif; 26 | $headingFont: 'Source Sans Pro', Helvetica, sans-serif; 27 | $headingTextShadow: none; 28 | $headingLetterSpacing: normal; 29 | $headingTextTransform: uppercase; 30 | $headingFontWeight: 600; 31 | $linkColor: #2a76dd; 32 | $linkColorHover: lighten( $linkColor, 15% ); 33 | $selectionBackgroundColor: lighten( $linkColor, 25% ); 34 | 35 | $heading1Size: 2.5em; 36 | $heading2Size: 1.6em; 37 | $heading3Size: 1.3em; 38 | $heading4Size: 1.0em; 39 | 40 | section.has-dark-background { 41 | &, h1, h2, h3, h4, h5, h6 { 42 | color: #fff; 43 | } 44 | } 45 | 46 | 47 | // Theme template ------------------------------ 48 | @import "../template/theme"; 49 | // --------------------------------------------- -------------------------------------------------------------------------------- /docs/css/theme/template/settings.scss: -------------------------------------------------------------------------------- 1 | // Base settings for all themes that can optionally be 2 | // overridden by the super-theme 3 | 4 | // Background of the presentation 5 | $backgroundColor: #2b2b2b; 6 | 7 | // Primary/body text 8 | $mainFont: 'Lato', sans-serif; 9 | $mainFontSize: 40px; 10 | $mainColor: #eee; 11 | 12 | // Vertical spacing between blocks of text 13 | $blockMargin: 20px; 14 | 15 | // Headings 16 | $headingMargin: 0 0 $blockMargin 0; 17 | $headingFont: 'League Gothic', Impact, sans-serif; 18 | $headingColor: #eee; 19 | $headingLineHeight: 1.2; 20 | $headingLetterSpacing: normal; 21 | $headingTextTransform: uppercase; 22 | $headingTextShadow: none; 23 | $headingFontWeight: normal; 24 | $heading1TextShadow: $headingTextShadow; 25 | 26 | $heading1Size: 3.77em; 27 | $heading2Size: 2.11em; 28 | $heading3Size: 1.55em; 29 | $heading4Size: 1.00em; 30 | 31 | $codeFont: monospace; 32 | 33 | // Links and actions 34 | $linkColor: #13DAEC; 35 | $linkColorHover: lighten( $linkColor, 20% ); 36 | 37 | // Text selection 38 | $selectionBackgroundColor: #FF5E99; 39 | $selectionColor: #fff; 40 | 41 | // Generates the presentation background, can be overridden 42 | // to return a background image or gradient 43 | @mixin bodyBackground() { 44 | background: $backgroundColor; 45 | } 46 | -------------------------------------------------------------------------------- /docs/images/OpenID_logo_2.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/OpenID_logo_2.svg.png -------------------------------------------------------------------------------- /docs/images/Valet_Ferrari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/Valet_Ferrari.png -------------------------------------------------------------------------------- /docs/images/agile-security-book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/agile-security-book.jpg -------------------------------------------------------------------------------- /docs/images/andreas_falk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/andreas_falk.jpg -------------------------------------------------------------------------------- /docs/images/authorization_code_schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/authorization_code_schema.png -------------------------------------------------------------------------------- /docs/images/automatic_role_mapping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/automatic_role_mapping.png -------------------------------------------------------------------------------- /docs/images/cropped-novatec-favicon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/cropped-novatec-favicon-192x192.png -------------------------------------------------------------------------------- /docs/images/cropped-novatec-favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/cropped-novatec-favicon-32x32.png -------------------------------------------------------------------------------- /docs/images/demo-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/demo-architecture.png -------------------------------------------------------------------------------- /docs/images/devops-handbook.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/devops-handbook.jpg -------------------------------------------------------------------------------- /docs/images/devtools_cookies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/devtools_cookies.png -------------------------------------------------------------------------------- /docs/images/implicit_schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/implicit_schema.png -------------------------------------------------------------------------------- /docs/images/iron-glad-java.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/iron-glad-java.jpg -------------------------------------------------------------------------------- /docs/images/jwt_generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/jwt_generator.png -------------------------------------------------------------------------------- /docs/images/jwt_generator_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/jwt_generator_result.png -------------------------------------------------------------------------------- /docs/images/jwt_io.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/jwt_io.png -------------------------------------------------------------------------------- /docs/images/jwt_io_decoded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/jwt_io_decoded.png -------------------------------------------------------------------------------- /docs/images/keycloak_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/keycloak_logo.png -------------------------------------------------------------------------------- /docs/images/keycloak_session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/keycloak_session.png -------------------------------------------------------------------------------- /docs/images/keycloak_sessions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/keycloak_sessions.png -------------------------------------------------------------------------------- /docs/images/kubernetes_session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/kubernetes_session.png -------------------------------------------------------------------------------- /docs/images/library_client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/library_client.png -------------------------------------------------------------------------------- /docs/images/manico_tweet_oauth2_not_authentication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/manico_tweet_oauth2_not_authentication.png -------------------------------------------------------------------------------- /docs/images/manico_xss_local_storage.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/manico_xss_local_storage.jpeg -------------------------------------------------------------------------------- /docs/images/manual_role_mapping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/manual_role_mapping.png -------------------------------------------------------------------------------- /docs/images/novatec-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/novatec-back.png -------------------------------------------------------------------------------- /docs/images/novatec-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/novatec-logo.jpg -------------------------------------------------------------------------------- /docs/images/novatec-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/novatec-logo.png -------------------------------------------------------------------------------- /docs/images/novatec_logo_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/novatec_logo_big.png -------------------------------------------------------------------------------- /docs/images/novatec_offices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/novatec_offices.png -------------------------------------------------------------------------------- /docs/images/oauth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/oauth.png -------------------------------------------------------------------------------- /docs/images/oauth2_in_action.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/oauth2_in_action.jpg -------------------------------------------------------------------------------- /docs/images/oauth2_protocol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/oauth2_protocol.png -------------------------------------------------------------------------------- /docs/images/oauth2_roles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/oauth2_roles.png -------------------------------------------------------------------------------- /docs/images/oauth_implicit_grant_attacks_d_fett.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/oauth_implicit_grant_attacks_d_fett.png -------------------------------------------------------------------------------- /docs/images/oidc-map-2014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/oidc-map-2014.png -------------------------------------------------------------------------------- /docs/images/oidc_roles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/oidc_roles.png -------------------------------------------------------------------------------- /docs/images/openredirector_spring_security.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/openredirector_spring_security.png -------------------------------------------------------------------------------- /docs/images/osw2019picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/osw2019picture.jpg -------------------------------------------------------------------------------- /docs/images/owasp-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/owasp-logo.png -------------------------------------------------------------------------------- /docs/images/security_session_grandja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/security_session_grandja.png -------------------------------------------------------------------------------- /docs/images/server_web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/server_web.png -------------------------------------------------------------------------------- /docs/images/spa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/spa.png -------------------------------------------------------------------------------- /docs/images/spring-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/spring-logo.png -------------------------------------------------------------------------------- /docs/images/spring_io_2019_workshop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/spring_io_2019_workshop.jpg -------------------------------------------------------------------------------- /docs/images/spring_io_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/spring_io_logo.png -------------------------------------------------------------------------------- /docs/images/spring_security_5_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/spring_security_5_2.png -------------------------------------------------------------------------------- /docs/images/spring_security_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/spring_security_new.png -------------------------------------------------------------------------------- /docs/images/spring_security_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/spring_security_old.png -------------------------------------------------------------------------------- /docs/images/spring_security_old.xml: -------------------------------------------------------------------------------- 1 | 7ZfBjpswEIafhiMSsVmXPW6T3baHbg9R1ao3Bw/g1mBqzEL69B2CgbBJ1K6qVaIqF7D/Gc+Mxx8IPLrM23eGl9lHLUB5JBCtR1ceIQt6G+KtU7a9EgW0F1IjhXOahLX8BU4MnFpLAdXM0WqtrCznYqyLAmI707gxupm7JVrNs5Y8hQNhHXN1qH6RwmZOXbDbyfAeZJq51BF50xtyPji7nVQZF7rZk+i9R5dGa9uP8nYJqmve0Jd+3cMJ61iYgcL+zYLm86fHrGHx3Uq0PHj8upIfvvkuyhNXtduwR5jCeG+rkhc4TrvxoG2eC4nG3Lg1u3X9Yj9rPRj8anead+hAwrKdjEOUqjSySP1N1wIXEMvvY87zoHyQG7WjNZpJIbPaiNF1IaBrR4DmJpMW1iWPO2uD9KKW2VzhbNHtQCq11Eqb3VoqOERJ3BVtjf4BexYWR7BJxnxPYCy0J89oMZ48PjKgc7Bmiy7DAuZgcU8LC9y8mdiLBi3bx85p3OGejqEnInDgoHgBIPRCAPEry7Gxxq8gro202ysxR4m5IecmJrwAYgZI/O/N9dVyHJQwPDcoNy8C5d+4OMDtOSia1zYjf4DiBD//PSuUnZsVdnms+HjV+NmZyLQ2cCXnKDkjEa9ADk6nr+edbe8fhN7/Bg== -------------------------------------------------------------------------------- /docs/images/threat-modeling-book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/threat-modeling-book.jpg -------------------------------------------------------------------------------- /docs/images/title_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/title_image.png -------------------------------------------------------------------------------- /docs/images/token_validation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/token_validation.png -------------------------------------------------------------------------------- /docs/images/token_validation.xml: -------------------------------------------------------------------------------- 1 | 5Vlbd9soEP41Pqf7kB6ELpYeE/eW9uxutsnZNI9EwjZnkVARvvXXdxBI1s2J102cun2ymBmGYb4PGPDInaTr95Lk8z9FQvkIo2Q9ct+MMHbcyIMfLdkYSYRdI5hJllijreCafaNWiKx0wRJatAyVEFyxvC2MRZbRWLVkREqxaptNBW+PmpMZ7QmuY8L70luWqLmVOkG0VXygbDa3Q4d4bBQpqYztTIo5ScSqIXLfjtyJFEKZr3Q9oVwnr8qL6fduh7YOTNJM7dPhn3B6s7yUwfTL+j1KVn/dsM/yzHpZEr6wEx7hgIO/i6kAtxC12thUBF8XolKcFSVQ52CAvXy9VcLXzP6WXu4rwYQzHacVQ5T3XVOQmTErMW4Nj6VYZAnVk0GgXs2Zotc5ibV2BdwD2VylHFpO3XtJpaLrnflyahSAvlSkVMkNmFQdfAucZa7n2faqwYOxlc0bFHAq7hLLvVntewsPfFiE/gda+FhofaaFWEjILUbXVEIaTwm40PvpgHOPBdz5Qs2FZN+IYiJroId0/BhdJpBDpnSyrqRYwtZ6Ush6XWT7wOJwCFj8XMB6A8B2kkSz5FwfRNCKOSkKFkMyCkWk6osb6aJrpr7ozL72bevO5ll/v1k3GxvbKJQU/9XnlKtZxDifCC5kGYubEBpO49qyoQnikN5PtcMM8mIGxn7VvquC0o3t2GWrGtxMnCa987SDLiTH7C2PnkqQoxlVD9hFw2xp0MEfYEMlk5TDMlm2wx1iiB3hSrByre44H4Iuycw0ba/mwdxx5IVtRzWFK0cmDz1HJWHraR/OYf9X5vD4pTiMT4HD2PPbG6p/IIeDzmLA0XE5HJwWh6nveAgNcfgCI4RQk8NOk8A2ip+Lws6OU/s4HI7CDofdAzncrRsdtB+HgT5k0zDLtUHxQMDYHxxnuySMxyddIOMfrkCdcKgC/ZdwlhClbwqX0BfdAJ114fnq4+3NH/vWkVARqvaqa6+LTGS0s4isCEafZXrpArmhlnUvdH3J4Pp+bhUpSxI9zGB12q5fn6BAdXFnGxyoUKOBpdA98Z+sPg2fH3YSx7Qofnvox3tAX99DmtiPnwv7aCf2uaTdq56lw5TEbTZ8oHxJdVqbHDiUNb3r6tXinsOBi9EnuqmVsryr9m6ij99Oa+f7xmegR6VuSlLGN0YL3Uial0rX9TQ9G1loa2onJcnOCsMy7SQTMiW8n4SPt5/Ki/ljj2EtkF744u13yO0Ee5I7eC5yV081x93Z/s7J1wX9/Ta3qFMaweX3hTc358dfrvfcoyrwL6HMFkVOY/O0djqvZt2Tad+1e0BRAs3tHxqmdN3+LeS+/Q4= -------------------------------------------------------------------------------- /docs/images/why_not_use_implicit_grant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/images/why_not_use_implicit_grant.png -------------------------------------------------------------------------------- /docs/lib/css/monokai.css: -------------------------------------------------------------------------------- 1 | /* 2 | Monokai style - ported by Luigi Maselli - http://grigio.org 3 | */ 4 | 5 | .hljs { 6 | display: block; 7 | overflow-x: auto; 8 | padding: 0.5em; 9 | background: #272822; 10 | color: #ddd; 11 | } 12 | 13 | .hljs-tag, 14 | .hljs-keyword, 15 | .hljs-selector-tag, 16 | .hljs-literal, 17 | .hljs-strong, 18 | .hljs-name { 19 | color: #f92672; 20 | } 21 | 22 | .hljs-code { 23 | color: #66d9ef; 24 | } 25 | 26 | .hljs-class .hljs-title { 27 | color: white; 28 | } 29 | 30 | .hljs-attribute, 31 | .hljs-symbol, 32 | .hljs-regexp, 33 | .hljs-link { 34 | color: #bf79db; 35 | } 36 | 37 | .hljs-string, 38 | .hljs-bullet, 39 | .hljs-subst, 40 | .hljs-title, 41 | .hljs-section, 42 | .hljs-emphasis, 43 | .hljs-type, 44 | .hljs-built_in, 45 | .hljs-builtin-name, 46 | .hljs-selector-attr, 47 | .hljs-selector-pseudo, 48 | .hljs-addition, 49 | .hljs-variable, 50 | .hljs-template-tag, 51 | .hljs-template-variable { 52 | color: #a6e22e; 53 | } 54 | 55 | .hljs-comment, 56 | .hljs-quote, 57 | .hljs-deletion, 58 | .hljs-meta { 59 | color: #75715e; 60 | } 61 | 62 | .hljs-keyword, 63 | .hljs-selector-tag, 64 | .hljs-literal, 65 | .hljs-doctag, 66 | .hljs-title, 67 | .hljs-section, 68 | .hljs-type, 69 | .hljs-selector-id { 70 | font-weight: bold; 71 | } 72 | -------------------------------------------------------------------------------- /docs/lib/css/zenburn.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Zenburn style from voldmar.ru (c) Vladimir Epifanov 4 | based on dark.css by Ivan Sagalaev 5 | 6 | */ 7 | 8 | .hljs { 9 | display: block; 10 | overflow-x: auto; 11 | padding: 0.5em; 12 | background: #3f3f3f; 13 | color: #dcdcdc; 14 | } 15 | 16 | .hljs-keyword, 17 | .hljs-selector-tag, 18 | .hljs-tag { 19 | color: #e3ceab; 20 | } 21 | 22 | .hljs-template-tag { 23 | color: #dcdcdc; 24 | } 25 | 26 | .hljs-number { 27 | color: #8cd0d3; 28 | } 29 | 30 | .hljs-variable, 31 | .hljs-template-variable, 32 | .hljs-attribute { 33 | color: #efdcbc; 34 | } 35 | 36 | .hljs-literal { 37 | color: #efefaf; 38 | } 39 | 40 | .hljs-subst { 41 | color: #8f8f8f; 42 | } 43 | 44 | .hljs-title, 45 | .hljs-name, 46 | .hljs-selector-id, 47 | .hljs-selector-class, 48 | .hljs-section, 49 | .hljs-type { 50 | color: #efef8f; 51 | } 52 | 53 | .hljs-symbol, 54 | .hljs-bullet, 55 | .hljs-link { 56 | color: #dca3a3; 57 | } 58 | 59 | .hljs-deletion, 60 | .hljs-string, 61 | .hljs-built_in, 62 | .hljs-builtin-name { 63 | color: #cc9393; 64 | } 65 | 66 | .hljs-addition, 67 | .hljs-comment, 68 | .hljs-quote, 69 | .hljs-meta { 70 | color: #7f9f7f; 71 | } 72 | 73 | 74 | .hljs-emphasis { 75 | font-style: italic; 76 | } 77 | 78 | .hljs-strong { 79 | font-weight: bold; 80 | } 81 | -------------------------------------------------------------------------------- /docs/lib/font/league-gothic/LICENSE: -------------------------------------------------------------------------------- 1 | SIL Open Font License (OFL) 2 | http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL 3 | -------------------------------------------------------------------------------- /docs/lib/font/league-gothic/league-gothic.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'League Gothic'; 3 | src: url('league-gothic.eot'); 4 | src: url('league-gothic.eot?#iefix') format('embedded-opentype'), 5 | url('league-gothic.woff') format('woff'), 6 | url('league-gothic.ttf') format('truetype'); 7 | 8 | font-weight: normal; 9 | font-style: normal; 10 | } -------------------------------------------------------------------------------- /docs/lib/font/league-gothic/league-gothic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/league-gothic/league-gothic.eot -------------------------------------------------------------------------------- /docs/lib/font/league-gothic/league-gothic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/league-gothic/league-gothic.ttf -------------------------------------------------------------------------------- /docs/lib/font/league-gothic/league-gothic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/league-gothic/league-gothic.woff -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-italic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-italic.eot -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-italic.ttf -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-italic.woff -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-regular.eot -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-regular.ttf -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-regular.woff -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-semibold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-semibold.eot -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-semibold.ttf -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-semibold.woff -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-semibolditalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-semibolditalic.eot -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-semibolditalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-semibolditalic.ttf -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro-semibolditalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/docs/lib/font/source-sans-pro/source-sans-pro-semibolditalic.woff -------------------------------------------------------------------------------- /docs/lib/font/source-sans-pro/source-sans-pro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Sans Pro'; 3 | src: url('source-sans-pro-regular.eot'); 4 | src: url('source-sans-pro-regular.eot?#iefix') format('embedded-opentype'), 5 | url('source-sans-pro-regular.woff') format('woff'), 6 | url('source-sans-pro-regular.ttf') format('truetype'); 7 | font-weight: normal; 8 | font-style: normal; 9 | } 10 | 11 | @font-face { 12 | font-family: 'Source Sans Pro'; 13 | src: url('source-sans-pro-italic.eot'); 14 | src: url('source-sans-pro-italic.eot?#iefix') format('embedded-opentype'), 15 | url('source-sans-pro-italic.woff') format('woff'), 16 | url('source-sans-pro-italic.ttf') format('truetype'); 17 | font-weight: normal; 18 | font-style: italic; 19 | } 20 | 21 | @font-face { 22 | font-family: 'Source Sans Pro'; 23 | src: url('source-sans-pro-semibold.eot'); 24 | src: url('source-sans-pro-semibold.eot?#iefix') format('embedded-opentype'), 25 | url('source-sans-pro-semibold.woff') format('woff'), 26 | url('source-sans-pro-semibold.ttf') format('truetype'); 27 | font-weight: 600; 28 | font-style: normal; 29 | } 30 | 31 | @font-face { 32 | font-family: 'Source Sans Pro'; 33 | src: url('source-sans-pro-semibolditalic.eot'); 34 | src: url('source-sans-pro-semibolditalic.eot?#iefix') format('embedded-opentype'), 35 | url('source-sans-pro-semibolditalic.woff') format('woff'), 36 | url('source-sans-pro-semibolditalic.ttf') format('truetype'); 37 | font-weight: 600; 38 | font-style: italic; 39 | } -------------------------------------------------------------------------------- /docs/lib/js/html5shiv.js: -------------------------------------------------------------------------------- 1 | document.createElement('header'); 2 | document.createElement('nav'); 3 | document.createElement('section'); 4 | document.createElement('article'); 5 | document.createElement('aside'); 6 | document.createElement('footer'); 7 | document.createElement('hgroup'); -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reveal.js", 3 | "version": "3.8.0", 4 | "description": "The HTML Presentation Framework", 5 | "homepage": "http://revealjs.com", 6 | "subdomain": "revealjs", 7 | "main": "js/reveal.js", 8 | "scripts": { 9 | "test": "grunt test", 10 | "start": "grunt serve", 11 | "build": "grunt" 12 | }, 13 | "author": { 14 | "name": "Hakim El Hattab", 15 | "email": "hakim.elhattab@gmail.com", 16 | "web": "http://hakim.se" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git://github.com/hakimel/reveal.js.git" 21 | }, 22 | "engines": { 23 | "node": ">=9.0.0" 24 | }, 25 | "devDependencies": { 26 | "express": "^4.16.2", 27 | "grunt": "^1.0.4", 28 | "grunt-cli": "^1.3.2", 29 | "grunt-autoprefixer": "^3.0.4", 30 | "grunt-contrib-connect": "^2.0.0", 31 | "grunt-contrib-cssmin": "^3.0.0", 32 | "grunt-contrib-jshint": "^2.0.0", 33 | "grunt-contrib-qunit": "^3.1.0", 34 | "grunt-contrib-uglify": "^3.3.0", 35 | "grunt-contrib-watch": "^1.1.0", 36 | "grunt-sass": "^3.0.2", 37 | "grunt-zip": "~0.17.1", 38 | "load-grunt-tasks": "^4.0.0", 39 | "node-sass": "^4.11.0", 40 | "mustache": "^2.3.0", 41 | "socket.io": "^2.2.0" 42 | }, 43 | "license": "MIT" 44 | } 45 | -------------------------------------------------------------------------------- /docs/plugin/markdown/example.md: -------------------------------------------------------------------------------- 1 | # Markdown Demo 2 | 3 | 4 | 5 | ## External 1.1 6 | 7 | Content 1.1 8 | 9 | Note: This will only appear in the speaker notes window. 10 | 11 | 12 | ## External 1.2 13 | 14 | Content 1.2 15 | 16 | 17 | 18 | ## External 2 19 | 20 | Content 2.1 21 | 22 | 23 | 24 | ## External 3.1 25 | 26 | Content 3.1 27 | 28 | 29 | ## External 3.2 30 | 31 | Content 3.2 32 | 33 | 34 | ## External 3.3 35 | 36 | ![External Image](https://s3.amazonaws.com/static.slid.es/logo/v2/slides-symbol-512x512.png) 37 | -------------------------------------------------------------------------------- /docs/plugin/multiplex/client.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var multiplex = Reveal.getConfig().multiplex; 3 | var socketId = multiplex.id; 4 | var socket = io.connect(multiplex.url); 5 | 6 | socket.on(multiplex.id, function(data) { 7 | // ignore data from sockets that aren't ours 8 | if (data.socketId !== socketId) { return; } 9 | if( window.location.host === 'localhost:1947' ) return; 10 | 11 | Reveal.setState(data.state); 12 | }); 13 | }()); 14 | -------------------------------------------------------------------------------- /docs/plugin/multiplex/master.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // Don't emit events from inside of notes windows 4 | if ( window.location.search.match( /receiver/gi ) ) { return; } 5 | 6 | var multiplex = Reveal.getConfig().multiplex; 7 | 8 | var socket = io.connect( multiplex.url ); 9 | 10 | function post() { 11 | 12 | var messageData = { 13 | state: Reveal.getState(), 14 | secret: multiplex.secret, 15 | socketId: multiplex.id 16 | }; 17 | 18 | socket.emit( 'multiplex-statechanged', messageData ); 19 | 20 | }; 21 | 22 | // post once the page is loaded, so the client follows also on "open URL". 23 | window.addEventListener( 'load', post ); 24 | 25 | // Monitor events that trigger a change in state 26 | Reveal.addEventListener( 'slidechanged', post ); 27 | Reveal.addEventListener( 'fragmentshown', post ); 28 | Reveal.addEventListener( 'fragmenthidden', post ); 29 | Reveal.addEventListener( 'overviewhidden', post ); 30 | Reveal.addEventListener( 'overviewshown', post ); 31 | Reveal.addEventListener( 'paused', post ); 32 | Reveal.addEventListener( 'resumed', post ); 33 | 34 | }()); 35 | -------------------------------------------------------------------------------- /docs/plugin/multiplex/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reveal-js-multiplex", 3 | "version": "1.0.0", 4 | "description": "reveal.js multiplex server", 5 | "homepage": "http://revealjs.com", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "engines": { 10 | "node": "~4.1.1" 11 | }, 12 | "dependencies": { 13 | "express": "~4.13.3", 14 | "grunt-cli": "~0.1.13", 15 | "mustache": "~2.2.1", 16 | "socket.io": "~1.3.7" 17 | }, 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /intro-labs/README.md: -------------------------------------------------------------------------------- 1 | # Intro Labs: Delegated Authorization using OAuth 2.0 2 | 3 | The intro labs are containing the following demos: 4 | 5 | * [Authorization Code Grant Flow Demo](auth-code-demo) 6 | * [Connecting a client app to GitHub API using OAuth 2.0](github-client) 7 | 8 | The first one shows all steps of the authorization code grant flow 9 | in detail to understand how this flow works. This is important for other concepts 10 | that are built upon this flow like the PKCE addition or OpenID Connect. 11 | 12 | The second one shows how the common predefined OAuth2 clients 13 | of spring security 5 can be used to quickly build clients 14 | for well known providers like GitHub, Google or Facebook. 15 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | /build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | 6 | ### STS ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | *.iws 18 | *.iml 19 | *.ipr 20 | /out/ 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.4.RELEASE' 3 | id 'java' 4 | } 5 | 6 | apply plugin: 'io.spring.dependency-management' 7 | 8 | group = 'com.example' 9 | version = '1.0.0-SNAPSHOT' 10 | sourceCompatibility = '8' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | implementation 'org.springframework.boot:spring-boot-starter-web' 18 | implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 19 | implementation 'org.springframework:spring-webflux' 20 | implementation 'io.projectreactor.netty:reactor-netty' 21 | implementation 'org.apache.commons:commons-lang3' 22 | runtimeOnly 'org.springframework.boot:spring-boot-devtools' 23 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 24 | testImplementation 'io.projectreactor:reactor-test' 25 | } 26 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/intro-labs/auth-code-demo/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'auth-code-demo' 7 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/src/main/java/com/example/authorizationcode/client/AuthorizationCodeDemo.java: -------------------------------------------------------------------------------- 1 | package com.example.authorizationcode.client; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AuthorizationCodeDemo { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(AuthorizationCodeDemo.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/src/main/java/com/example/authorizationcode/client/config/WebClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.authorizationcode.client.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.reactive.function.client.WebClient; 6 | 7 | @Configuration 8 | public class WebClientConfiguration { 9 | 10 | @Bean 11 | WebClient webClient() { 12 | return WebClient.builder().build(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/src/main/java/com/example/authorizationcode/client/web/TokenRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.authorizationcode.client.web; 2 | 3 | public class TokenRequest { 4 | 5 | private String code; 6 | private String state; 7 | 8 | public String getCode() { 9 | return code; 10 | } 11 | 12 | public void setCode(String code) { 13 | this.code = code; 14 | } 15 | 16 | public String getState() { 17 | return state; 18 | } 19 | 20 | public void setState(String state) { 21 | this.state = state; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/src/main/java/com/example/authorizationcode/client/web/TokenResponse.java: -------------------------------------------------------------------------------- 1 | package com.example.authorizationcode.client.web; 2 | 3 | import java.util.Base64; 4 | 5 | import static java.nio.charset.StandardCharsets.UTF_8; 6 | 7 | public class TokenResponse { 8 | 9 | private String access_token; 10 | private String refresh_token; 11 | private int expires_in; 12 | private String token_type; 13 | private String scope; 14 | 15 | public String getAccess_token() { 16 | return access_token; 17 | } 18 | 19 | public String getDecodedAccessToken() { 20 | if (getAccess_token() != null) { 21 | return new String(Base64.getDecoder().decode(getAccess_token()), UTF_8); 22 | } else { 23 | return "N/A"; 24 | } 25 | } 26 | 27 | public void setAccess_token(String access_token) { 28 | this.access_token = access_token; 29 | } 30 | 31 | public String getRefresh_token() { 32 | return refresh_token; 33 | } 34 | 35 | public void setRefresh_token(String refresh_token) { 36 | this.refresh_token = refresh_token; 37 | } 38 | 39 | public int getExpires_in() { 40 | return expires_in; 41 | } 42 | 43 | public void setExpires_in(int expires_in) { 44 | this.expires_in = expires_in; 45 | } 46 | 47 | public String getToken_type() { 48 | return token_type; 49 | } 50 | 51 | public void setToken_type(String token_type) { 52 | this.token_type = token_type; 53 | } 54 | 55 | public String getScope() { 56 | return scope; 57 | } 58 | 59 | public void setScope(String scope) { 60 | this.scope = scope; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | servlet: 3 | context-path: /client 4 | port: 9095 5 | 6 | spring: 7 | thymeleaf: 8 | cache: false 9 | 10 | logging: 11 | level: 12 | root: info 13 | org: 14 | springframework: 15 | web: info 16 | 17 | democlient: 18 | authorization: 19 | endpoint: http://localhost:8080/auth/realms/workshop/protocol/openid-connect/auth 20 | clientid: demo-client 21 | response-type: code 22 | redirect-uri: http://localhost:9095/client/callback 23 | scope: offline_access 24 | token: 25 | endpoint: http://localhost:8080/auth/realms/workshop/protocol/openid-connect/token 26 | clientid: demo-client 27 | client-secret: b3ec9d3f-d1ee-4a18-b4ba-05d832c15293 28 | redirect-uri: http://localhost:9095/client/callback 29 | introspection: 30 | endpoint: http://localhost:8080/auth/realms/workshop/protocol/openid-connect/token/introspect 31 | 32 | 33 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/src/main/resources/templates/authcode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OAuth 2.0 Client 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |

OAuth 2.0 Client Callback

13 | 14 |
15 |
Step 2: Exchange authorization code for access token
17 |
18 | 19 |
20 |
21 | 22 |
    23 |
  • 24 |
  • 25 |
26 |
27 |
28 |
29 |

Token Request

30 | 31 |

32 | 33 | Request Token 35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OAuth 2.0 Client 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |

OAuth 2.0 Client

13 | 14 |
15 |

An error occurred

16 | 17 |
    18 |
  • 19 |
  • 20 |
21 | 22 | Home 23 | 24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /intro-labs/auth-code-demo/src/main/resources/templates/introspection.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OAuth 2.0 Client 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 |

OAuth 2.0 Client

15 | 16 |

Token Introspection

17 | 18 |

Result

19 | 20 |

21 | 22 | Home 23 | 24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /intro-labs/github-client/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | /build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | 6 | ### STS ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | *.iws 18 | *.iml 19 | *.ipr 20 | /out/ 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | bin/ 32 | 33 | client_secrets.txt 34 | -------------------------------------------------------------------------------- /intro-labs/github-client/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.4.RELEASE' 3 | id 'java' 4 | } 5 | 6 | apply plugin: 'io.spring.dependency-management' 7 | 8 | group = 'com.example' 9 | version = '1.0.0-SNAPSHOT' 10 | sourceCompatibility = '1.8' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' 18 | implementation 'org.springframework.boot:spring-boot-starter-web' 19 | implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 20 | implementation 'org.springframework:spring-webflux' 21 | implementation 'io.projectreactor.netty:reactor-netty' 22 | runtimeOnly 'org.springframework.boot:spring-boot-devtools' 23 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 24 | } 25 | -------------------------------------------------------------------------------- /intro-labs/github-client/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/intro-labs/github-client/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /intro-labs/github-client/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /intro-labs/github-client/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'github-client' 7 | -------------------------------------------------------------------------------- /intro-labs/github-client/src/main/java/com/example/github/GitHubClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.github; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class GitHubClientApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(GitHubClientApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /intro-labs/github-client/src/main/java/com/example/github/config/WebClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.github.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; 6 | import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; 7 | import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction; 8 | import org.springframework.web.reactive.function.client.WebClient; 9 | 10 | @Configuration 11 | public class WebClientConfiguration { 12 | 13 | @Bean 14 | WebClient webClient( 15 | ClientRegistrationRepository clientRegistrationRepository, 16 | OAuth2AuthorizedClientRepository authorizedClientRepository) { 17 | ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = 18 | new ServletOAuth2AuthorizedClientExchangeFilterFunction( 19 | clientRegistrationRepository, authorizedClientRepository); 20 | oauth2.setDefaultClientRegistrationId("github"); 21 | return WebClient.builder().apply(oauth2.oauth2Configuration()).build(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /intro-labs/github-client/src/main/java/com/example/github/restapi/GitHubNotification.java: -------------------------------------------------------------------------------- 1 | package com.example.github.restapi; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | /** GitHub Notifications. */ 6 | public class GitHubNotification { 7 | private String id; 8 | private GitHubRepository repository; 9 | private GitHubSubject subject; 10 | private String reason; 11 | private LocalDateTime updatedAt; 12 | private LocalDateTime lastReadAt; 13 | 14 | public String getId() { 15 | return id; 16 | } 17 | 18 | public LocalDateTime getLastReadAt() { 19 | return lastReadAt; 20 | } 21 | 22 | public void setLastread_at(LocalDateTime lastReadAt) { 23 | this.lastReadAt = lastReadAt; 24 | } 25 | 26 | public LocalDateTime getUpdatedAt() { 27 | return updatedAt; 28 | } 29 | 30 | public void setUpdated_at(LocalDateTime updatedAt) { 31 | this.updatedAt = updatedAt; 32 | } 33 | 34 | public String getReason() { 35 | return reason; 36 | } 37 | 38 | public void setReason(String reason) { 39 | this.reason = reason; 40 | } 41 | 42 | public GitHubSubject getSubject() { 43 | return subject; 44 | } 45 | 46 | public void setSubject(GitHubSubject subject) { 47 | this.subject = subject; 48 | } 49 | 50 | public GitHubRepository getRepository() { 51 | return repository; 52 | } 53 | 54 | public void setRepository(GitHubRepository repository) { 55 | this.repository = repository; 56 | } 57 | 58 | public void setId(String id) { 59 | this.id = id; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /intro-labs/github-client/src/main/java/com/example/github/restapi/GitHubRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.github.restapi; 2 | 3 | public class GitHubRepository { 4 | private String id; 5 | private String name; 6 | private String fullName; 7 | 8 | public String getId() { 9 | return id; 10 | } 11 | 12 | public String getFullName() { 13 | return fullName; 14 | } 15 | 16 | public void setFull_name(String fullName) { 17 | this.fullName = fullName; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name = name; 26 | } 27 | 28 | public void setId(String id) { 29 | this.id = id; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /intro-labs/github-client/src/main/java/com/example/github/restapi/GitHubSubject.java: -------------------------------------------------------------------------------- 1 | package com.example.github.restapi; 2 | 3 | public class GitHubSubject { 4 | private String title; 5 | private String url; 6 | private String type; 7 | private String latestCommentUrl; 8 | 9 | public String getTitle() { 10 | return title; 11 | } 12 | 13 | public String getLatestCommentUrl() { 14 | return latestCommentUrl; 15 | } 16 | 17 | public void setLatestCommentUrl(String latestCommentUrl) { 18 | this.latestCommentUrl = latestCommentUrl; 19 | } 20 | 21 | public String getType() { 22 | return type; 23 | } 24 | 25 | public void setType(String type) { 26 | this.type = type; 27 | } 28 | 29 | public String getUrl() { 30 | return url; 31 | } 32 | 33 | public void setUrl(String url) { 34 | this.url = url; 35 | } 36 | 37 | public void setTitle(String title) { 38 | this.title = title; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /intro-labs/github-client/src/main/java/com/example/github/restapi/UserIdController.java: -------------------------------------------------------------------------------- 1 | package com.example.github.restapi; 2 | 3 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 4 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; 5 | import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; 6 | import org.springframework.security.oauth2.core.user.OAuth2User; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.Model; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | 11 | @Controller 12 | public class UserIdController { 13 | 14 | @GetMapping("/") 15 | public String index( 16 | Model model, 17 | @RegisteredOAuth2AuthorizedClient(registrationId = "github") 18 | OAuth2AuthorizedClient authorizedClient, 19 | @AuthenticationPrincipal OAuth2User oauth2User) { 20 | model.addAttribute("userName", oauth2User.getName()); 21 | model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName()); 22 | model.addAttribute("userAttributes", oauth2User.getAttributes()); 23 | return "index"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /intro-labs/github-client/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | thymeleaf: 3 | cache: false 4 | security: 5 | oauth2: 6 | client: 7 | registration: 8 | github: 9 | client-id: 10 | client-secret: 11 | scope: 12 | - read:user 13 | - notifications 14 | redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}' 15 | github: 16 | base: 17 | url: https://api.github.com/ 18 | 19 | logging: 20 | level: 21 | root: INFO 22 | org.springframework.security: DEBUG 23 | 24 | server: 25 | port: 9090 -------------------------------------------------------------------------------- /intro-labs/github-client/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Spring Security - OpenID Connect Login 6 | 7 | 8 | 9 |
10 |
11 | User: 12 |
13 |
 
14 |
15 |
16 | 17 |
18 |
19 |
20 |

OAuth 2.0 Login with Spring Security

21 |
22 | You are successfully logged in 23 | via the OAuth 2.0 Client 24 |
25 |
 
26 |
27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 | User Attributes: 35 |
    36 |
  • 37 | : 39 |
  • 40 |
41 |
42 | 43 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /build/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | bin/ -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/README.md: -------------------------------------------------------------------------------- 1 | # Complete library server application with automatic mapping 2 | 3 | This is the completed reference of the library resource server application that is using 4 | the automatic scope mapping provided by Spring Security 5. 5 | 6 | ![Spring IO Workshop 2019](../../docs/images/automatic_role_mapping.png) 7 | 8 | See [Spring Security 5 resource server authorization](https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2resourceserver-authorization) 9 | for details on automatic scope mapping. 10 | 11 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab1/library-server-complete-automatic/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'library-server-complete-automatic' 7 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/CompleteAutomaticLibraryServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CompleteAutomaticLibraryServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CompleteAutomaticLibraryServerApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/api/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.security.access.AccessDeniedException; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | 11 | @RestControllerAdvice 12 | public class ErrorHandler { 13 | 14 | @ExceptionHandler(RuntimeException.class) 15 | public ResponseEntity handle(RuntimeException ex) { 16 | Logger logger = LoggerFactory.getLogger(this.getClass()); 17 | logger.error(ex.getMessage(), ex); 18 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); 19 | } 20 | 21 | @ExceptionHandler(Exception.class) 22 | public ResponseEntity handle(Exception ex) { 23 | Logger logger = LoggerFactory.getLogger(this.getClass()); 24 | logger.error(ex.getMessage(), ex); 25 | return ResponseEntity.badRequest().body(ex.getMessage()); 26 | } 27 | 28 | @ExceptionHandler(AccessDeniedException.class) 29 | public ResponseEntity handle(AccessDeniedException ex) { 30 | Logger logger = LoggerFactory.getLogger(this.getClass()); 31 | logger.error(ex.getMessage(), ex); 32 | return ResponseEntity.status(HttpStatus.FORBIDDEN) 33 | .body("User is not authorized to use this resource"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/api/resource/BookListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import org.springframework.hateoas.ResourceSupport; 4 | 5 | import java.util.Collection; 6 | 7 | public class BookListResource extends ResourceSupport { 8 | 9 | private final Collection books; 10 | 11 | public BookListResource(Collection books) { 12 | this.books = books; 13 | } 14 | 15 | public Collection getBooks() { 16 | return books; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/api/resource/ModifyingUserResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import com.example.library.server.common.Role; 4 | 5 | import javax.validation.constraints.NotNull; 6 | import javax.validation.constraints.Pattern; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.UUID; 10 | 11 | public class ModifyingUserResource extends UserResource { 12 | 13 | @NotNull 14 | @Pattern(regexp = "[A-Za-z0-9_!]{8,100}") 15 | private String password; 16 | 17 | private List roles = new ArrayList<>(); 18 | 19 | public ModifyingUserResource() {} 20 | 21 | public ModifyingUserResource( 22 | UUID identifier, 23 | String email, 24 | String firstName, 25 | String lastName, 26 | String password, 27 | List roles) { 28 | super(identifier, email, firstName, lastName); 29 | this.password = password; 30 | this.roles = roles; 31 | } 32 | 33 | public String getPassword() { 34 | return password; 35 | } 36 | 37 | public void setPassword(String password) { 38 | this.password = password; 39 | } 40 | 41 | public List getRoles() { 42 | return roles; 43 | } 44 | 45 | public void setRoles(List roles) { 46 | this.roles = roles; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/api/resource/UserListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import org.springframework.hateoas.ResourceSupport; 4 | 5 | import java.util.Collection; 6 | 7 | public class UserListResource extends ResourceSupport { 8 | 9 | private final Collection users; 10 | 11 | public UserListResource(Collection users) { 12 | this.users = users; 13 | } 14 | 15 | public Collection getUsers() { 16 | return users; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/api/resource/assembler/BookListResourceAssembler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource.assembler; 2 | 3 | import com.example.library.server.api.BookRestController; 4 | import com.example.library.server.api.resource.BookListResource; 5 | import com.example.library.server.api.resource.BookResource; 6 | import com.example.library.server.dataaccess.Book; 7 | import org.springframework.hateoas.mvc.ResourceAssemblerSupport; 8 | 9 | import java.util.Collection; 10 | import java.util.stream.Collectors; 11 | 12 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 13 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 14 | 15 | public class BookListResourceAssembler 16 | extends ResourceAssemblerSupport, BookListResource> { 17 | 18 | public BookListResourceAssembler() { 19 | super(BookRestController.class, BookListResource.class); 20 | } 21 | 22 | @Override 23 | public BookListResource toResource(Collection books) { 24 | 25 | BookListResource bookListResource = 26 | new BookListResource( 27 | books.stream() 28 | .map(b -> new BookResourceAssembler().toResource(b)) 29 | .collect(Collectors.toList())); 30 | bookListResource.add( 31 | linkTo(methodOn(BookRestController.class).getAllBooks()).withSelfRel(), 32 | linkTo(methodOn(BookRestController.class).createBook(new BookResource())) 33 | .withRel("create")); 34 | return bookListResource; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/api/resource/assembler/UserResourceAssembler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource.assembler; 2 | 3 | import com.example.library.server.api.UserRestController; 4 | import com.example.library.server.api.resource.UserResource; 5 | import com.example.library.server.dataaccess.User; 6 | import org.springframework.hateoas.mvc.ResourceAssemblerSupport; 7 | 8 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 9 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 10 | 11 | public class UserResourceAssembler extends ResourceAssemblerSupport { 12 | 13 | public UserResourceAssembler() { 14 | super(UserRestController.class, UserResource.class); 15 | } 16 | 17 | @Override 18 | public UserResource toResource(User user) { 19 | UserResource userResource = new UserResource(user); 20 | userResource.add( 21 | linkTo(methodOn(UserRestController.class).getUser(user.getIdentifier())).withSelfRel()); 22 | return userResource; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/common/Role.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.common; 2 | 3 | public enum Role { 4 | LIBRARY_USER, 5 | 6 | LIBRARY_CURATOR, 7 | 8 | LIBRARY_ADMIN 9 | } 10 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/config/IdGeneratorConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.util.IdGenerator; 6 | import org.springframework.util.JdkIdGenerator; 7 | 8 | @Configuration 9 | public class IdGeneratorConfiguration { 10 | 11 | @Bean 12 | public IdGenerator idGenerator() { 13 | return new JdkIdGenerator(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/config/WebSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 | import org.springframework.security.config.http.SessionCreationPolicy; 8 | 9 | @Configuration 10 | @EnableGlobalMethodSecurity(prePostEnabled = true) 11 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 12 | 13 | @Override 14 | protected void configure(HttpSecurity http) throws Exception { 15 | http.sessionManagement() 16 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 17 | .and() 18 | .csrf() 19 | .disable() 20 | .authorizeRequests() 21 | .anyRequest() 22 | .fullyAuthenticated() 23 | .and() 24 | .oauth2ResourceServer() 25 | .jwt(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/dataaccess/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import org.springframework.data.jpa.repository.EntityGraph; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | 9 | public interface BookRepository extends JpaRepository { 10 | 11 | Optional findOneByIdentifier(UUID identifier); 12 | 13 | @EntityGraph(attributePaths = "borrowedBy") 14 | Optional findOneWithDetailsByIdentifier(UUID identifier); 15 | 16 | void deleteBookByIdentifier(UUID identifier); 17 | } 18 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/dataaccess/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import org.springframework.data.jpa.repository.EntityGraph; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | 9 | public interface UserRepository extends JpaRepository { 10 | 11 | @EntityGraph(attributePaths = "roles") 12 | Optional findOneByEmail(String email); 13 | 14 | Optional findOneByIdentifier(UUID identifier); 15 | 16 | void deleteUserByIdentifier(UUID identifier); 17 | } 18 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/security/LibraryUser.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import com.example.library.server.dataaccess.User; 4 | import org.springframework.security.core.GrantedAuthority; 5 | import org.springframework.security.core.authority.AuthorityUtils; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | 8 | import java.util.Collection; 9 | 10 | public class LibraryUser extends User implements UserDetails { 11 | 12 | public LibraryUser(User user) { 13 | super(user); 14 | } 15 | 16 | @Override 17 | public Collection getAuthorities() { 18 | return AuthorityUtils.createAuthorityList( 19 | getRoles().stream().map(r -> "ROLE_" + r).toArray(String[]::new)); 20 | } 21 | 22 | @Override 23 | public String getPassword() { 24 | return "n/a"; 25 | } 26 | 27 | @Override 28 | public String getUsername() { 29 | return getEmail(); 30 | } 31 | 32 | @Override 33 | public boolean isAccountNonExpired() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public boolean isAccountNonLocked() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public boolean isCredentialsNonExpired() { 44 | return true; 45 | } 46 | 47 | @Override 48 | public boolean isEnabled() { 49 | return true; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/security/LibraryUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import com.example.library.server.business.UserService; 4 | import org.springframework.security.core.userdetails.UserDetails; 5 | import org.springframework.security.core.userdetails.UserDetailsService; 6 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class LibraryUserDetailsService implements UserDetailsService { 11 | 12 | private final UserService userService; 13 | 14 | public LibraryUserDetailsService(UserService userService) { 15 | this.userService = userService; 16 | } 17 | 18 | @Override 19 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 20 | return userService 21 | .findOneByEmail(username) 22 | .map(LibraryUser::new) 23 | .orElseThrow( 24 | () -> new UsernameNotFoundException(String.format("No user found for %s", username))); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/java/com/example/library/server/security/PreAuthorizeNotRequired.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Custom annotation without any function but just to document that no pre-authorization is required 12 | * here by intention. 13 | */ 14 | @Target({ElementType.METHOD, ElementType.TYPE}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Inherited 17 | @Documented 18 | public @interface PreAuthorizeNotRequired {} 19 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | management: 2 | endpoints: 3 | web: 4 | exposure: 5 | include: '*' 6 | endpoint: 7 | health: 8 | show-details: always 9 | spring: 10 | jpa: 11 | open-in-view: false 12 | jackson: 13 | date-format: com.fasterxml.jackson.databind.util.StdDateFormat 14 | default-property-inclusion: non_null 15 | security: 16 | oauth2: 17 | resourceserver: 18 | jwt: 19 | issuer-uri: http://localhost:8080/auth/realms/workshop 20 | 21 | logging: 22 | level: 23 | org: 24 | springframework: 25 | security: debug 26 | server: 27 | error: 28 | include-stacktrace: never 29 | port: 9091 30 | servlet: 31 | context-path: /library-server 32 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/test/java/com/example/library/server/dataaccess/BookBuilder.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public final class BookBuilder { 8 | 9 | private UUID identifier = UUID.randomUUID(); 10 | private String isbn = "978-123-456-789"; 11 | private String title = "A book title"; 12 | private String description = "A book description"; 13 | private List authors = new ArrayList<>(); 14 | private boolean borrowed = false; 15 | private User user = null; 16 | 17 | public static BookBuilder book() { 18 | return new BookBuilder(); 19 | } 20 | 21 | private BookBuilder() {} 22 | 23 | public BookBuilder withIdentifier(UUID identifier) { 24 | this.identifier = identifier; 25 | return this; 26 | } 27 | 28 | public BookBuilder withIsbn(String isbn) { 29 | this.isbn = isbn; 30 | return this; 31 | } 32 | 33 | public BookBuilder withTitle(String title) { 34 | this.title = title; 35 | return this; 36 | } 37 | 38 | public BookBuilder withDescription(String description) { 39 | this.description = description; 40 | return this; 41 | } 42 | 43 | public BookBuilder withAuthor(String author) { 44 | this.authors.add(author); 45 | return this; 46 | } 47 | 48 | public BookBuilder borrowWith(User user) { 49 | this.borrowed = true; 50 | this.user = user; 51 | return this; 52 | } 53 | 54 | public Book build() { 55 | return new Book(identifier, isbn, title, description, authors, borrowed, user); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/test/java/com/example/library/server/dataaccess/UserBuilder.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public final class UserBuilder { 8 | 9 | private UUID identifier = UUID.randomUUID(); 10 | 11 | private String email = "first.last@example.com"; 12 | 13 | private String firstName = "First"; 14 | 15 | private String lastName = "Last"; 16 | 17 | private List roles = new ArrayList<>(); 18 | 19 | public static UserBuilder user() { 20 | return new UserBuilder(); 21 | } 22 | 23 | private UserBuilder() {} 24 | 25 | public UserBuilder withIdentifier(UUID identifier) { 26 | this.identifier = identifier; 27 | return this; 28 | } 29 | 30 | public UserBuilder withEmail(String email) { 31 | this.email = email; 32 | return this; 33 | } 34 | 35 | public UserBuilder withFirstName(String firstName) { 36 | this.firstName = firstName; 37 | return this; 38 | } 39 | 40 | public UserBuilder withLastName(String lastName) { 41 | this.lastName = lastName; 42 | return this; 43 | } 44 | 45 | public UserBuilder addRole(String role) { 46 | this.roles.add(role); 47 | return this; 48 | } 49 | 50 | public User build() { 51 | return new User(identifier, email, firstName, lastName, roles); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lab1/library-server-complete-automatic/src/test/java/com/example/library/server/test/WithMockJwt.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.test; 2 | 3 | import org.springframework.security.test.context.support.WithSecurityContext; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Inherited; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | 12 | @Target({ElementType.METHOD, ElementType.TYPE}) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Inherited 15 | @Documented 16 | @WithSecurityContext(factory = WithMockJwtSecurityContextFactory.class) 17 | public @interface WithMockJwt { 18 | 19 | String value() default ""; 20 | 21 | String username() default ""; 22 | 23 | String email() default ""; 24 | 25 | String[] scopes() default {"user"}; 26 | } 27 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /build/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | bin/ -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/README.md: -------------------------------------------------------------------------------- 1 | # Complete library server application with custom mapping 2 | 3 | This is the completed reference of the library resource server application that is using 4 | the customized authorities and user mapping provided by Spring Security 5. 5 | 6 | ![Spring IO Workshop 2019](../../docs/images/manual_role_mapping.png) 7 | 8 | See [Spring Security 5 resource server authorization](https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2resourceserver-authorization-extraction) 9 | for details on custom authorities mapping. -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab1/library-server-complete-custom/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'library-server-complete-custom' 7 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/CompleteCustomLibraryServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CompleteCustomLibraryServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CompleteCustomLibraryServerApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/api/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.security.access.AccessDeniedException; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | 11 | @RestControllerAdvice 12 | public class ErrorHandler { 13 | 14 | @ExceptionHandler(RuntimeException.class) 15 | public ResponseEntity handle(RuntimeException ex) { 16 | Logger logger = LoggerFactory.getLogger(this.getClass()); 17 | logger.error(ex.getMessage(), ex); 18 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); 19 | } 20 | 21 | @ExceptionHandler(Exception.class) 22 | public ResponseEntity handle(Exception ex) { 23 | Logger logger = LoggerFactory.getLogger(this.getClass()); 24 | logger.error(ex.getMessage(), ex); 25 | return ResponseEntity.badRequest().body(ex.getMessage()); 26 | } 27 | 28 | @ExceptionHandler(AccessDeniedException.class) 29 | public ResponseEntity handle(AccessDeniedException ex) { 30 | Logger logger = LoggerFactory.getLogger(this.getClass()); 31 | logger.error(ex.getMessage(), ex); 32 | return ResponseEntity.status(HttpStatus.FORBIDDEN) 33 | .body("User is not authorized to use this resource"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/api/resource/BookListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import org.springframework.hateoas.ResourceSupport; 4 | 5 | import java.util.Collection; 6 | 7 | public class BookListResource extends ResourceSupport { 8 | 9 | private final Collection books; 10 | 11 | public BookListResource(Collection books) { 12 | this.books = books; 13 | } 14 | 15 | public Collection getBooks() { 16 | return books; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/api/resource/ModifyingUserResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import com.example.library.server.common.Role; 4 | 5 | import javax.validation.constraints.NotNull; 6 | import javax.validation.constraints.Pattern; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.UUID; 10 | 11 | public class ModifyingUserResource extends UserResource { 12 | 13 | @NotNull 14 | @Pattern(regexp = "[A-Za-z0-9_!]{8,100}") 15 | private String password; 16 | 17 | private List roles = new ArrayList<>(); 18 | 19 | public ModifyingUserResource() {} 20 | 21 | public ModifyingUserResource( 22 | UUID identifier, 23 | String email, 24 | String firstName, 25 | String lastName, 26 | String password, 27 | List roles) { 28 | super(identifier, email, firstName, lastName); 29 | this.password = password; 30 | this.roles = roles; 31 | } 32 | 33 | public String getPassword() { 34 | return password; 35 | } 36 | 37 | public void setPassword(String password) { 38 | this.password = password; 39 | } 40 | 41 | public List getRoles() { 42 | return roles; 43 | } 44 | 45 | public void setRoles(List roles) { 46 | this.roles = roles; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/api/resource/UserListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import org.springframework.hateoas.ResourceSupport; 4 | 5 | import java.util.Collection; 6 | 7 | public class UserListResource extends ResourceSupport { 8 | 9 | private final Collection users; 10 | 11 | public UserListResource(Collection users) { 12 | this.users = users; 13 | } 14 | 15 | public Collection getUsers() { 16 | return users; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/api/resource/assembler/BookListResourceAssembler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource.assembler; 2 | 3 | import com.example.library.server.api.BookRestController; 4 | import com.example.library.server.api.resource.BookListResource; 5 | import com.example.library.server.api.resource.BookResource; 6 | import com.example.library.server.dataaccess.Book; 7 | import org.springframework.hateoas.mvc.ResourceAssemblerSupport; 8 | 9 | import java.util.Collection; 10 | import java.util.stream.Collectors; 11 | 12 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 13 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 14 | 15 | public class BookListResourceAssembler 16 | extends ResourceAssemblerSupport, BookListResource> { 17 | 18 | public BookListResourceAssembler() { 19 | super(BookRestController.class, BookListResource.class); 20 | } 21 | 22 | @Override 23 | public BookListResource toResource(Collection books) { 24 | 25 | BookListResource bookListResource = 26 | new BookListResource( 27 | books.stream() 28 | .map(b -> new BookResourceAssembler().toResource(b)) 29 | .collect(Collectors.toList())); 30 | bookListResource.add( 31 | linkTo(methodOn(BookRestController.class).getAllBooks()).withSelfRel(), 32 | linkTo(methodOn(BookRestController.class).createBook(new BookResource())) 33 | .withRel("create")); 34 | return bookListResource; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/api/resource/assembler/UserResourceAssembler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource.assembler; 2 | 3 | import com.example.library.server.api.UserRestController; 4 | import com.example.library.server.api.resource.UserResource; 5 | import com.example.library.server.dataaccess.User; 6 | import org.springframework.hateoas.mvc.ResourceAssemblerSupport; 7 | 8 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 9 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 10 | 11 | public class UserResourceAssembler extends ResourceAssemblerSupport { 12 | 13 | public UserResourceAssembler() { 14 | super(UserRestController.class, UserResource.class); 15 | } 16 | 17 | @Override 18 | public UserResource toResource(User user) { 19 | UserResource userResource = new UserResource(user); 20 | userResource.add( 21 | linkTo(methodOn(UserRestController.class).getUser(user.getIdentifier())).withSelfRel()); 22 | return userResource; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/common/Role.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.common; 2 | 3 | public enum Role { 4 | LIBRARY_USER, 5 | 6 | LIBRARY_CURATOR, 7 | 8 | LIBRARY_ADMIN 9 | } 10 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/config/IdGeneratorConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.util.IdGenerator; 6 | import org.springframework.util.JdkIdGenerator; 7 | 8 | @Configuration 9 | public class IdGeneratorConfiguration { 10 | 11 | @Bean 12 | public IdGenerator idGenerator() { 13 | return new JdkIdGenerator(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/dataaccess/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import org.springframework.data.jpa.repository.EntityGraph; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | 9 | public interface BookRepository extends JpaRepository { 10 | 11 | Optional findOneByIdentifier(UUID identifier); 12 | 13 | @EntityGraph(attributePaths = "borrowedBy") 14 | Optional findOneWithDetailsByIdentifier(UUID identifier); 15 | 16 | void deleteBookByIdentifier(UUID identifier); 17 | } 18 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/dataaccess/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import org.springframework.data.jpa.repository.EntityGraph; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | 9 | public interface UserRepository extends JpaRepository { 10 | 11 | @EntityGraph(attributePaths = "roles") 12 | Optional findOneByEmail(String email); 13 | 14 | Optional findOneByIdentifier(UUID identifier); 15 | 16 | void deleteUserByIdentifier(UUID identifier); 17 | } 18 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/security/AudienceValidator.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import org.springframework.security.oauth2.core.OAuth2Error; 4 | import org.springframework.security.oauth2.core.OAuth2TokenValidator; 5 | import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; 6 | import org.springframework.security.oauth2.jwt.Jwt; 7 | 8 | /** Validator for expected audience in access tokens. */ 9 | public class AudienceValidator implements OAuth2TokenValidator { 10 | 11 | private OAuth2Error error = 12 | new OAuth2Error("invalid_token", "The required audience 'library-service' is missing", null); 13 | 14 | public OAuth2TokenValidatorResult validate(Jwt jwt) { 15 | if (jwt.getAudience().contains("library-service")) { 16 | return OAuth2TokenValidatorResult.success(); 17 | } else { 18 | return OAuth2TokenValidatorResult.failure(error); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/security/LibraryUser.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import com.example.library.server.dataaccess.User; 4 | import org.springframework.security.core.GrantedAuthority; 5 | import org.springframework.security.core.authority.AuthorityUtils; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | 8 | import java.util.Collection; 9 | 10 | public class LibraryUser extends User implements UserDetails { 11 | 12 | public LibraryUser(User user) { 13 | super(user); 14 | } 15 | 16 | @Override 17 | public Collection getAuthorities() { 18 | return AuthorityUtils.createAuthorityList( 19 | getRoles().stream().map(r -> "ROLE_" + r).toArray(String[]::new)); 20 | } 21 | 22 | @Override 23 | public String getPassword() { 24 | return "n/a"; 25 | } 26 | 27 | @Override 28 | public String getUsername() { 29 | return getEmail(); 30 | } 31 | 32 | @Override 33 | public boolean isAccountNonExpired() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public boolean isAccountNonLocked() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public boolean isCredentialsNonExpired() { 44 | return true; 45 | } 46 | 47 | @Override 48 | public boolean isEnabled() { 49 | return true; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/security/LibraryUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import com.example.library.server.business.UserService; 4 | import org.springframework.security.core.userdetails.UserDetails; 5 | import org.springframework.security.core.userdetails.UserDetailsService; 6 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class LibraryUserDetailsService implements UserDetailsService { 11 | 12 | private final UserService userService; 13 | 14 | public LibraryUserDetailsService(UserService userService) { 15 | this.userService = userService; 16 | } 17 | 18 | @Override 19 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 20 | return userService 21 | .findOneByEmail(username) 22 | .map(LibraryUser::new) 23 | .orElseThrow( 24 | () -> new UsernameNotFoundException(String.format("No user found for %s", username))); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/security/LibraryUserRolesJwtAuthenticationConverter.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import org.springframework.core.convert.converter.Converter; 4 | import org.springframework.security.authentication.AbstractAuthenticationToken; 5 | import org.springframework.security.authentication.BadCredentialsException; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.oauth2.jwt.Jwt; 8 | 9 | import java.util.Optional; 10 | 11 | /** JWT converter that takes the roles from persistent user roles. */ 12 | @SuppressWarnings("unused") 13 | public class LibraryUserRolesJwtAuthenticationConverter 14 | implements Converter { 15 | 16 | private final LibraryUserDetailsService libraryUserDetailsService; 17 | 18 | public LibraryUserRolesJwtAuthenticationConverter( 19 | LibraryUserDetailsService libraryUserDetailsService) { 20 | this.libraryUserDetailsService = libraryUserDetailsService; 21 | } 22 | 23 | @Override 24 | public AbstractAuthenticationToken convert(Jwt jwt) { 25 | return Optional.ofNullable(libraryUserDetailsService.loadUserByUsername(jwt.getSubject())) 26 | .map(u -> new UsernamePasswordAuthenticationToken(u, "n/a", u.getAuthorities())) 27 | .orElseThrow(() -> new BadCredentialsException("User not found")); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/java/com/example/library/server/security/PreAuthorizeNotRequired.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Custom annotation without any function but just to document that no pre-authorization is required 12 | * here by intention. 13 | */ 14 | @Target({ElementType.METHOD, ElementType.TYPE}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Inherited 17 | @Documented 18 | public @interface PreAuthorizeNotRequired {} 19 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | management: 2 | endpoints: 3 | web: 4 | exposure: 5 | include: '*' 6 | endpoint: 7 | health: 8 | show-details: always 9 | spring: 10 | jpa: 11 | open-in-view: false 12 | jackson: 13 | date-format: com.fasterxml.jackson.databind.util.StdDateFormat 14 | default-property-inclusion: non_null 15 | security: 16 | oauth2: 17 | resourceserver: 18 | jwt: 19 | issuer-uri: http://localhost:8080/auth/realms/workshop 20 | 21 | logging: 22 | level: 23 | org: 24 | springframework: 25 | security: debug 26 | server: 27 | error: 28 | include-stacktrace: never 29 | port: 9091 30 | servlet: 31 | context-path: /library-server 32 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/test/java/com/example/library/server/dataaccess/BookBuilder.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public final class BookBuilder { 8 | 9 | private UUID identifier = UUID.randomUUID(); 10 | private String isbn = "978-123-456-789"; 11 | private String title = "A book title"; 12 | private String description = "A book description"; 13 | private List authors = new ArrayList<>(); 14 | private boolean borrowed = false; 15 | private User user = null; 16 | 17 | private BookBuilder() {} 18 | 19 | public static BookBuilder book() { 20 | return new BookBuilder(); 21 | } 22 | 23 | public BookBuilder withIdentifier(UUID identifier) { 24 | this.identifier = identifier; 25 | return this; 26 | } 27 | 28 | public BookBuilder withIsbn(String isbn) { 29 | this.isbn = isbn; 30 | return this; 31 | } 32 | 33 | public BookBuilder withTitle(String title) { 34 | this.title = title; 35 | return this; 36 | } 37 | 38 | public BookBuilder withDescription(String description) { 39 | this.description = description; 40 | return this; 41 | } 42 | 43 | public BookBuilder withAuthor(String author) { 44 | this.authors.add(author); 45 | return this; 46 | } 47 | 48 | public BookBuilder borrowWith(User user) { 49 | this.borrowed = true; 50 | this.user = user; 51 | return this; 52 | } 53 | 54 | public Book build() { 55 | return new Book(identifier, isbn, title, description, authors, borrowed, user); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/test/java/com/example/library/server/dataaccess/UserBuilder.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public final class UserBuilder { 8 | 9 | private UUID identifier = UUID.randomUUID(); 10 | 11 | private String email = "first.last@example.com"; 12 | 13 | private String firstName = "First"; 14 | 15 | private String lastName = "Last"; 16 | 17 | private List roles = new ArrayList<>(); 18 | 19 | private UserBuilder() {} 20 | 21 | public static UserBuilder user() { 22 | return new UserBuilder(); 23 | } 24 | 25 | public UserBuilder withIdentifier(UUID identifier) { 26 | this.identifier = identifier; 27 | return this; 28 | } 29 | 30 | public UserBuilder withEmail(String email) { 31 | this.email = email; 32 | return this; 33 | } 34 | 35 | public UserBuilder withFirstName(String firstName) { 36 | this.firstName = firstName; 37 | return this; 38 | } 39 | 40 | public UserBuilder withLastName(String lastName) { 41 | this.lastName = lastName; 42 | return this; 43 | } 44 | 45 | public UserBuilder addRole(String role) { 46 | this.roles.add(role); 47 | return this; 48 | } 49 | 50 | public User build() { 51 | return new User(identifier, email, firstName, lastName, roles); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lab1/library-server-complete-custom/src/test/java/com/example/library/server/test/WithMockLibraryUser.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.test; 2 | 3 | import org.springframework.security.test.context.support.WithSecurityContext; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Inherited; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | 12 | @Target({ElementType.METHOD, ElementType.TYPE}) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Inherited 15 | @Documented 16 | @WithSecurityContext(factory = WithMockLibraryUserSecurityContextFactory.class) 17 | public @interface WithMockLibraryUser { 18 | 19 | String[] roles() default {"USER"}; 20 | } 21 | -------------------------------------------------------------------------------- /lab1/library-server-initial/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /build/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | bin/ -------------------------------------------------------------------------------- /lab1/library-server-initial/README.md: -------------------------------------------------------------------------------- 1 | # Initial library server application 2 | 3 | This is the initial library resource server application that is the starting point 4 | for the hands-on part to implement an OAuth2/OIDC resource server. 5 | 6 | ![Spring IO Workshop 2019](../../docs/images/demo-architecture.png) 7 | 8 | The completed reference for the resource server (based on this initial application) 9 | can be found [here](../library-server-complete-custom/README.md). 10 | 11 | See [Spring Security 5 resource server](https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2resourceserver) 12 | for details on how to build and configure a resource server. -------------------------------------------------------------------------------- /lab1/library-server-initial/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab1/library-server-initial/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lab1/library-server-initial/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lab1/library-server-initial/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'library-server-initial' 7 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/Lab1InitialLibraryServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Lab1InitialLibraryServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Lab1InitialLibraryServerApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/api/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.security.access.AccessDeniedException; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | 11 | @RestControllerAdvice 12 | public class ErrorHandler { 13 | 14 | @ExceptionHandler(RuntimeException.class) 15 | public ResponseEntity handle(RuntimeException ex) { 16 | Logger logger = LoggerFactory.getLogger(this.getClass()); 17 | logger.error(ex.getMessage(), ex); 18 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); 19 | } 20 | 21 | @ExceptionHandler(Exception.class) 22 | public ResponseEntity handle(Exception ex) { 23 | Logger logger = LoggerFactory.getLogger(this.getClass()); 24 | logger.error(ex.getMessage(), ex); 25 | return ResponseEntity.badRequest().body(ex.getMessage()); 26 | } 27 | 28 | @ExceptionHandler(AccessDeniedException.class) 29 | public ResponseEntity handle(AccessDeniedException ex) { 30 | Logger logger = LoggerFactory.getLogger(this.getClass()); 31 | logger.error(ex.getMessage(), ex); 32 | return ResponseEntity.status(HttpStatus.FORBIDDEN) 33 | .body("User is not authorized to use this resource"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/api/resource/BookListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import org.springframework.hateoas.ResourceSupport; 4 | 5 | import java.util.Collection; 6 | 7 | public class BookListResource extends ResourceSupport { 8 | 9 | private final Collection books; 10 | 11 | public BookListResource(Collection books) { 12 | this.books = books; 13 | } 14 | 15 | public Collection getBooks() { 16 | return books; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/api/resource/ModifyingUserResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import com.example.library.server.common.Role; 4 | 5 | import javax.validation.constraints.NotNull; 6 | import javax.validation.constraints.Pattern; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.UUID; 10 | 11 | public class ModifyingUserResource extends UserResource { 12 | 13 | @NotNull 14 | @Pattern(regexp = "[A-Za-z0-9_!]{8,100}") 15 | private String password; 16 | 17 | private List roles = new ArrayList<>(); 18 | 19 | public ModifyingUserResource() {} 20 | 21 | public ModifyingUserResource( 22 | UUID identifier, 23 | String email, 24 | String firstName, 25 | String lastName, 26 | String password, 27 | List roles) { 28 | super(identifier, email, firstName, lastName); 29 | this.password = password; 30 | this.roles = roles; 31 | } 32 | 33 | public String getPassword() { 34 | return password; 35 | } 36 | 37 | public void setPassword(String password) { 38 | this.password = password; 39 | } 40 | 41 | public List getRoles() { 42 | return roles; 43 | } 44 | 45 | public void setRoles(List roles) { 46 | this.roles = roles; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/api/resource/UserListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import org.springframework.hateoas.ResourceSupport; 4 | 5 | import java.util.Collection; 6 | 7 | public class UserListResource extends ResourceSupport { 8 | 9 | private final Collection users; 10 | 11 | public UserListResource(Collection users) { 12 | this.users = users; 13 | } 14 | 15 | public Collection getUsers() { 16 | return users; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/api/resource/assembler/BookListResourceAssembler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource.assembler; 2 | 3 | import com.example.library.server.api.BookRestController; 4 | import com.example.library.server.api.resource.BookListResource; 5 | import com.example.library.server.api.resource.BookResource; 6 | import com.example.library.server.dataaccess.Book; 7 | import org.springframework.hateoas.mvc.ResourceAssemblerSupport; 8 | 9 | import java.util.Collection; 10 | import java.util.stream.Collectors; 11 | 12 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 13 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 14 | 15 | public class BookListResourceAssembler 16 | extends ResourceAssemblerSupport, BookListResource> { 17 | 18 | public BookListResourceAssembler() { 19 | super(BookRestController.class, BookListResource.class); 20 | } 21 | 22 | @Override 23 | public BookListResource toResource(Collection books) { 24 | 25 | BookListResource bookListResource = 26 | new BookListResource( 27 | books.stream() 28 | .map(b -> new BookResourceAssembler().toResource(b)) 29 | .collect(Collectors.toList())); 30 | bookListResource.add( 31 | linkTo(methodOn(BookRestController.class).getAllBooks()).withSelfRel(), 32 | linkTo(methodOn(BookRestController.class).createBook(new BookResource())) 33 | .withRel("create")); 34 | return bookListResource; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/api/resource/assembler/UserResourceAssembler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource.assembler; 2 | 3 | import com.example.library.server.api.UserRestController; 4 | import com.example.library.server.api.resource.UserResource; 5 | import com.example.library.server.dataaccess.User; 6 | import org.springframework.hateoas.mvc.ResourceAssemblerSupport; 7 | 8 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 9 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 10 | 11 | public class UserResourceAssembler extends ResourceAssemblerSupport { 12 | 13 | public UserResourceAssembler() { 14 | super(UserRestController.class, UserResource.class); 15 | } 16 | 17 | @Override 18 | public UserResource toResource(User user) { 19 | UserResource userResource = new UserResource(user); 20 | userResource.add( 21 | linkTo(methodOn(UserRestController.class).getUser(user.getIdentifier())).withSelfRel()); 22 | return userResource; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/common/Role.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.common; 2 | 3 | public enum Role { 4 | LIBRARY_USER, 5 | 6 | LIBRARY_CURATOR, 7 | 8 | LIBRARY_ADMIN 9 | } 10 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/config/IdGeneratorConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.util.IdGenerator; 6 | import org.springframework.util.JdkIdGenerator; 7 | 8 | @Configuration 9 | public class IdGeneratorConfiguration { 10 | 11 | @Bean 12 | public IdGenerator idGenerator() { 13 | return new JdkIdGenerator(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/config/WebSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 8 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | 11 | @Configuration 12 | @EnableGlobalMethodSecurity(prePostEnabled = true) 13 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 14 | 15 | @Override 16 | protected void configure(HttpSecurity http) throws Exception { 17 | http.csrf().disable().httpBasic().and().authorizeRequests().anyRequest().fullyAuthenticated(); 18 | } 19 | 20 | @Bean 21 | PasswordEncoder passwordEncoder() { 22 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/dataaccess/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import org.springframework.data.jpa.repository.EntityGraph; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | 9 | public interface BookRepository extends JpaRepository { 10 | 11 | Optional findOneByIdentifier(UUID identifier); 12 | 13 | @EntityGraph(attributePaths = "borrowedBy") 14 | Optional findOneWithDetailsByIdentifier(UUID identifier); 15 | 16 | void deleteBookByIdentifier(UUID identifier); 17 | } 18 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/dataaccess/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import org.springframework.data.jpa.repository.EntityGraph; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | 9 | public interface UserRepository extends JpaRepository { 10 | 11 | @EntityGraph(attributePaths = "roles") 12 | Optional findOneByEmail(String email); 13 | 14 | Optional findOneByIdentifier(UUID identifier); 15 | 16 | void deleteUserByIdentifier(UUID identifier); 17 | } 18 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/security/LibraryUser.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import com.example.library.server.dataaccess.User; 4 | import org.springframework.security.core.GrantedAuthority; 5 | import org.springframework.security.core.authority.AuthorityUtils; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | 8 | import java.util.Collection; 9 | 10 | public class LibraryUser extends User implements UserDetails { 11 | 12 | public LibraryUser(User user) { 13 | super(user); 14 | } 15 | 16 | @Override 17 | public Collection getAuthorities() { 18 | return AuthorityUtils.createAuthorityList( 19 | getRoles().stream().map(r -> "ROLE_" + r).toArray(String[]::new)); 20 | } 21 | 22 | @Override 23 | public String getUsername() { 24 | return getEmail(); 25 | } 26 | 27 | @Override 28 | public boolean isAccountNonExpired() { 29 | return true; 30 | } 31 | 32 | @Override 33 | public boolean isAccountNonLocked() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public boolean isCredentialsNonExpired() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public boolean isEnabled() { 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/security/LibraryUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import com.example.library.server.business.UserService; 4 | import org.springframework.security.core.userdetails.UserDetails; 5 | import org.springframework.security.core.userdetails.UserDetailsService; 6 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class LibraryUserDetailsService implements UserDetailsService { 11 | 12 | private final UserService userService; 13 | 14 | public LibraryUserDetailsService(UserService userService) { 15 | this.userService = userService; 16 | } 17 | 18 | @Override 19 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 20 | return userService 21 | .findOneByEmail(username) 22 | .map(LibraryUser::new) 23 | .orElseThrow( 24 | () -> new UsernameNotFoundException(String.format("No user found for %s", username))); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/java/com/example/library/server/security/PreAuthorizeNotRequired.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Custom annotation without any function but just to document that no pre-authorization is required 12 | * here by intention. 13 | */ 14 | @Target({ElementType.METHOD, ElementType.TYPE}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Inherited 17 | @Documented 18 | public @interface PreAuthorizeNotRequired {} 19 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | management: 2 | endpoints: 3 | web: 4 | exposure: 5 | include: '*' 6 | endpoint: 7 | health: 8 | show-details: always 9 | spring: 10 | jpa: 11 | open-in-view: false 12 | jackson: 13 | date-format: com.fasterxml.jackson.databind.util.StdDateFormat 14 | default-property-inclusion: non_null 15 | 16 | logging: 17 | level: 18 | org: 19 | springframework: 20 | security: debug 21 | server: 22 | error: 23 | include-stacktrace: never 24 | port: 9091 25 | servlet: 26 | context-path: /library-server 27 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/test/java/com/example/library/server/dataaccess/BookBuilder.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public final class BookBuilder { 8 | 9 | private UUID identifier = UUID.randomUUID(); 10 | private String isbn = "978-123-456-789"; 11 | private String title = "A book title"; 12 | private String description = "A book description"; 13 | private List authors = new ArrayList<>(); 14 | private boolean borrowed = false; 15 | private User user = null; 16 | 17 | public static BookBuilder book() { 18 | return new BookBuilder(); 19 | } 20 | 21 | private BookBuilder() {} 22 | 23 | public BookBuilder withIdentifier(UUID identifier) { 24 | this.identifier = identifier; 25 | return this; 26 | } 27 | 28 | public BookBuilder withIsbn(String isbn) { 29 | this.isbn = isbn; 30 | return this; 31 | } 32 | 33 | public BookBuilder withTitle(String title) { 34 | this.title = title; 35 | return this; 36 | } 37 | 38 | public BookBuilder withDescription(String description) { 39 | this.description = description; 40 | return this; 41 | } 42 | 43 | public BookBuilder withAuthor(String author) { 44 | this.authors.add(author); 45 | return this; 46 | } 47 | 48 | public BookBuilder borrowWith(User user) { 49 | this.borrowed = true; 50 | this.user = user; 51 | return this; 52 | } 53 | 54 | public Book build() { 55 | return new Book(identifier, isbn, title, description, authors, borrowed, user); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/test/java/com/example/library/server/dataaccess/UserBuilder.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public final class UserBuilder { 8 | 9 | private UUID identifier = UUID.randomUUID(); 10 | 11 | private String email = "first.last@example.com"; 12 | 13 | private String password = "secret"; 14 | 15 | private String firstName = "First"; 16 | 17 | private String lastName = "Last"; 18 | 19 | private List roles = new ArrayList<>(); 20 | 21 | public static UserBuilder user() { 22 | return new UserBuilder(); 23 | } 24 | 25 | private UserBuilder() {} 26 | 27 | public UserBuilder withIdentifier(UUID identifier) { 28 | this.identifier = identifier; 29 | return this; 30 | } 31 | 32 | public UserBuilder withEmail(String email) { 33 | this.email = email; 34 | return this; 35 | } 36 | 37 | public UserBuilder withPassword(String password) { 38 | this.password = password; 39 | return this; 40 | } 41 | 42 | public UserBuilder withFirstName(String firstName) { 43 | this.firstName = firstName; 44 | return this; 45 | } 46 | 47 | public UserBuilder withLastName(String lastName) { 48 | this.lastName = lastName; 49 | return this; 50 | } 51 | 52 | public UserBuilder addRole(String role) { 53 | this.roles.add(role); 54 | return this; 55 | } 56 | 57 | public User build() { 58 | return new User(identifier, email, password, firstName, lastName, roles); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lab1/library-server-initial/src/test/java/com/example/library/server/test/WithMockLibraryUser.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.test; 2 | 3 | import org.springframework.security.test.context.support.WithSecurityContext; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Inherited; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | 12 | @Target({ElementType.METHOD, ElementType.TYPE}) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Inherited 15 | @Documented 16 | @WithSecurityContext(factory = WithMockLibraryUserSecurityContextFactory.class) 17 | public @interface WithMockLibraryUser { 18 | 19 | String[] roles() default {"USER"}; 20 | } 21 | -------------------------------------------------------------------------------- /lab2/library-client-complete/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | /build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | 6 | ### STS ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | *.iws 18 | *.iml 19 | *.ipr 20 | /out/ 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | -------------------------------------------------------------------------------- /lab2/library-client-complete/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.4.RELEASE' 3 | id 'com.adarshr.test-logger' version '1.6.0' 4 | id 'java' 5 | } 6 | 7 | apply plugin: 'io.spring.dependency-management' 8 | 9 | group = 'com.example' 10 | version = '1.0.0-SNAPSHOT' 11 | sourceCompatibility = '1.8' 12 | 13 | repositories { 14 | mavenCentral() 15 | } 16 | 17 | dependencies { 18 | implementation 'org.springframework.boot:spring-boot-starter-actuator' 19 | implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' 20 | implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 21 | implementation 'org.springframework.boot:spring-boot-starter-web' 22 | implementation 'org.springframework.boot:spring-boot-starter-webflux' 23 | implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' 24 | runtimeOnly 'org.springframework.boot:spring-boot-devtools' 25 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 26 | testImplementation 'io.projectreactor:reactor-test' 27 | } 28 | -------------------------------------------------------------------------------- /lab2/library-client-complete/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab2/library-client-complete/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lab2/library-client-complete/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lab2/library-client-complete/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'library-client-complete' 7 | -------------------------------------------------------------------------------- /lab2/library-client-complete/src/main/java/com/example/library/client/LibraryClientCompleteApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class LibraryClientCompleteApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(LibraryClientCompleteApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab2/library-client-complete/src/main/java/com/example/library/client/config/WebClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; 6 | import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; 7 | import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction; 8 | import org.springframework.web.reactive.function.client.WebClient; 9 | 10 | @Configuration 11 | public class WebClientConfiguration { 12 | 13 | @Bean 14 | WebClient webClient( 15 | ClientRegistrationRepository clientRegistrations, 16 | OAuth2AuthorizedClientRepository authorizedClients) { 17 | ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = 18 | new ServletOAuth2AuthorizedClientExchangeFilterFunction( 19 | clientRegistrations, authorizedClients); 20 | oauth2.setDefaultOAuth2AuthorizedClient(true); 21 | oauth2.setDefaultClientRegistrationId("keycloak"); 22 | return WebClient.builder().apply(oauth2.oauth2Configuration()).build(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lab2/library-client-complete/src/main/java/com/example/library/client/web/BookListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.web; 2 | 3 | import java.util.Collection; 4 | 5 | public class BookListResource { 6 | 7 | private Collection books; 8 | 9 | public BookListResource() {} 10 | 11 | public BookListResource(Collection books) { 12 | this.books = books; 13 | } 14 | 15 | public Collection getBooks() { 16 | return books; 17 | } 18 | 19 | public void setBooks(Collection books) { 20 | this.books = books; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lab2/library-client-complete/src/main/java/com/example/library/client/web/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.web; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | 9 | @ControllerAdvice 10 | public class ErrorHandler { 11 | 12 | @ExceptionHandler(AccessDeniedException.class) 13 | public ResponseEntity handle(AccessDeniedException ex) { 14 | return ResponseEntity.status(HttpStatus.FORBIDDEN) 15 | .body("You are not authorized to access this resource"); 16 | } 17 | 18 | @ExceptionHandler(IllegalArgumentException.class) 19 | public ResponseEntity handle(IllegalArgumentException ex) { 20 | return ResponseEntity.badRequest().body(ex.getMessage()); 21 | } 22 | 23 | @ExceptionHandler(Exception.class) 24 | public ResponseEntity handle(Exception ex) { 25 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lab2/library-client-complete/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | servlet: 3 | context-path: /library-client 4 | port: 9090 5 | error: 6 | include-stacktrace: never 7 | 8 | spring: 9 | thymeleaf: 10 | cache: false 11 | security: 12 | oauth2: 13 | client: 14 | registration: 15 | keycloak: 16 | client-id: 'library-client' 17 | client-secret: '9584640c-3804-4dcd-997b-93593cfb9ea7' 18 | authorizationGrantType: authorization_code 19 | redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}' 20 | scope: openid 21 | provider: 22 | keycloak: 23 | issuerUri: http://localhost:8080/auth/realms/workshop 24 | user-name-attribute: name 25 | 26 | logging: 27 | level: 28 | root: info 29 | org: 30 | springframework: 31 | web: info 32 | 33 | library: 34 | server: http://localhost:9091/library-server 35 | -------------------------------------------------------------------------------- /lab2/library-client-complete/src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library Client 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |

Library Client

13 | 14 |
15 |

An error occurred

16 | 17 |
    18 |
  • 19 |
  • 20 |
21 | 22 | Home 23 | 24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /lab2/library-client-complete/src/test/java/com/example/library/client/LibraryClientCompleteApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.boot.test.mock.mockito.MockBean; 7 | import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | 10 | @RunWith(SpringRunner.class) 11 | @SpringBootTest 12 | public class LibraryClientCompleteApplicationTests { 13 | 14 | @SuppressWarnings("unused") 15 | @MockBean 16 | private ClientRegistrationRepository clientRegistrationRepository; 17 | 18 | @Test 19 | public void contextLoads() {} 20 | } 21 | -------------------------------------------------------------------------------- /lab2/library-client-initial/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | /build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | 6 | ### STS ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | *.iws 18 | *.iml 19 | *.ipr 20 | /out/ 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | -------------------------------------------------------------------------------- /lab2/library-client-initial/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.4.RELEASE' 3 | id 'com.adarshr.test-logger' version '1.6.0' 4 | id 'java' 5 | } 6 | 7 | apply plugin: 'io.spring.dependency-management' 8 | 9 | group = 'com.example' 10 | version = '1.0.0-SNAPSHOT' 11 | sourceCompatibility = '1.8' 12 | 13 | repositories { 14 | mavenCentral() 15 | } 16 | 17 | dependencies { 18 | implementation('org.springframework.boot:spring-boot-starter-actuator') 19 | implementation('org.springframework.boot:spring-boot-starter-security') 20 | implementation('org.springframework.boot:spring-boot-starter-thymeleaf') 21 | implementation('org.springframework.boot:spring-boot-starter-web') 22 | implementation('org.springframework.boot:spring-boot-starter-webflux') 23 | implementation('org.thymeleaf.extras:thymeleaf-extras-springsecurity5') 24 | runtimeOnly('org.springframework.boot:spring-boot-devtools') 25 | testImplementation('org.springframework.boot:spring-boot-starter-test') 26 | testImplementation('io.projectreactor:reactor-test') 27 | } 28 | -------------------------------------------------------------------------------- /lab2/library-client-initial/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab2/library-client-initial/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lab2/library-client-initial/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lab2/library-client-initial/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'library-client-initial' 7 | -------------------------------------------------------------------------------- /lab2/library-client-initial/src/main/java/com/example/library/client/LibraryClientInitialApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class LibraryClientInitialApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(LibraryClientInitialApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab2/library-client-initial/src/main/java/com/example/library/client/config/WebClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.reactive.function.client.WebClient; 6 | 7 | @Configuration 8 | public class WebClientConfiguration { 9 | 10 | @Bean 11 | WebClient webClient() { 12 | return WebClient.builder().build(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lab2/library-client-initial/src/main/java/com/example/library/client/config/WebSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 6 | 7 | @Configuration 8 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 9 | 10 | @Override 11 | protected void configure(HttpSecurity http) throws Exception { 12 | http.httpBasic().and().authorizeRequests().anyRequest().fullyAuthenticated(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lab2/library-client-initial/src/main/java/com/example/library/client/web/BookListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.web; 2 | 3 | import java.util.Collection; 4 | 5 | public class BookListResource { 6 | 7 | private Collection books; 8 | 9 | public BookListResource() {} 10 | 11 | public BookListResource(Collection books) { 12 | this.books = books; 13 | } 14 | 15 | public Collection getBooks() { 16 | return books; 17 | } 18 | 19 | public void setBooks(Collection books) { 20 | this.books = books; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lab2/library-client-initial/src/main/java/com/example/library/client/web/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.web; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | 9 | @ControllerAdvice 10 | public class ErrorHandler { 11 | 12 | @ExceptionHandler(AccessDeniedException.class) 13 | public ResponseEntity handle(AccessDeniedException ex) { 14 | return ResponseEntity.status(HttpStatus.FORBIDDEN) 15 | .body("You are not authorized to access this resource"); 16 | } 17 | 18 | @ExceptionHandler(IllegalArgumentException.class) 19 | public ResponseEntity handle(IllegalArgumentException ex) { 20 | return ResponseEntity.badRequest().body(ex.getMessage()); 21 | } 22 | 23 | @ExceptionHandler(Exception.class) 24 | public ResponseEntity handle(Exception ex) { 25 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lab2/library-client-initial/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | servlet: 3 | context-path: /library-client 4 | port: 9090 5 | error: 6 | include-stacktrace: never 7 | 8 | spring: 9 | thymeleaf: 10 | cache: false 11 | security: 12 | user: 13 | password: secret 14 | 15 | logging: 16 | level: 17 | root: info 18 | org: 19 | springframework: 20 | web: info 21 | 22 | library: 23 | server: http://localhost:9091/library-server 24 | 25 | -------------------------------------------------------------------------------- /lab2/library-client-initial/src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library Client 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |

Library Client

13 | 14 |
15 |

An error occurred

16 | 17 |
    18 |
  • 19 |
  • 20 |
21 | 22 | Home 23 | 24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /lab2/library-client-initial/src/test/java/com/example/library/client/LibraryClientInitialApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class LibraryClientInitialApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() {} 14 | } 15 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | /build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | 6 | ### STS ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | *.iws 18 | *.iml 19 | *.ipr 20 | /out/ 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.4.RELEASE' 3 | id 'java' 4 | } 5 | 6 | apply plugin: 'io.spring.dependency-management' 7 | 8 | group = 'com.example' 9 | version = '1.0.0-SNAPSHOT' 10 | sourceCompatibility = '1.8' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' 18 | implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 19 | implementation 'org.springframework.boot:spring-boot-starter-webflux' 20 | runtimeOnly 'org.springframework.boot:spring-boot-devtools' 21 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 22 | } 23 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab3/library-client-credentials-complete/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'library-client-credentials-complete' 7 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/src/main/java/com/example/library/client/credentials/LibraryClientCredentialsCompleteApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class LibraryClientCredentialsCompleteApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(LibraryClientCredentialsCompleteApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/src/main/java/com/example/library/client/credentials/config/WebClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.reactive.function.client.WebClient; 6 | 7 | @Configuration 8 | public class WebClientConfiguration { 9 | 10 | @Bean 11 | WebClient webClient() { 12 | return WebClient.builder().build(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/src/main/java/com/example/library/client/credentials/config/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; 5 | import org.springframework.security.config.web.server.ServerHttpSecurity; 6 | import org.springframework.security.web.server.SecurityWebFilterChain; 7 | 8 | @EnableWebFluxSecurity 9 | public class WebSecurityConfig { 10 | 11 | @Bean 12 | public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { 13 | http.authorizeExchange() 14 | .anyExchange() 15 | .permitAll() 16 | .and() 17 | .httpBasic() 18 | .disable() 19 | .formLogin() 20 | .disable() 21 | .oauth2Client(); 22 | return http.build(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/src/main/java/com/example/library/client/credentials/web/BookListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials.web; 2 | 3 | import java.util.Collection; 4 | 5 | public class BookListResource { 6 | 7 | private Collection books; 8 | 9 | public BookListResource() {} 10 | 11 | public BookListResource(Collection books) { 12 | this.books = books; 13 | } 14 | 15 | public Collection getBooks() { 16 | return books; 17 | } 18 | 19 | public void setBooks(Collection books) { 20 | this.books = books; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/src/main/java/com/example/library/client/credentials/web/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials.web; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | 9 | @ControllerAdvice 10 | public class ErrorHandler { 11 | 12 | @ExceptionHandler(AccessDeniedException.class) 13 | public ResponseEntity handle(AccessDeniedException ex) { 14 | return ResponseEntity.status(HttpStatus.FORBIDDEN) 15 | .body("You are not authorized to access this resource"); 16 | } 17 | 18 | @ExceptionHandler(IllegalArgumentException.class) 19 | public ResponseEntity handle(IllegalArgumentException ex) { 20 | return ResponseEntity.badRequest().body(ex.getMessage()); 21 | } 22 | 23 | @ExceptionHandler(Exception.class) 24 | public ResponseEntity handle(Exception ex) { 25 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9092 3 | error: 4 | include-stacktrace: never 5 | 6 | spring: 7 | thymeleaf: 8 | cache: false 9 | security: 10 | user: 11 | password: secret 12 | oauth2: 13 | client: 14 | registration: 15 | keycloak_client: 16 | client-id: 'library-client' 17 | client-secret: '9584640c-3804-4dcd-997b-93593cfb9ea7' 18 | authorizationGrantType: client_credentials 19 | provider: 20 | keycloak_client: 21 | tokenUri: http://localhost:8080/auth/realms/workshop/protocol/openid-connect/token 22 | 23 | logging: 24 | level: 25 | root: info 26 | org: 27 | springframework: 28 | web: info 29 | 30 | library: 31 | server: http://localhost:9091/library-server 32 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library Client 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |

Library Client

13 |

Client Credentials Flow

14 | 15 |
16 |

An error occurred

17 | 18 |
    19 |
  • 20 |
  • 21 |
22 | 23 | Home 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-complete/src/test/java/com/example/library/client/credentials/LibraryClientCredentialsCompleteApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class LibraryClientCredentialsCompleteApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() {} 14 | } 15 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | /build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | 6 | ### STS ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | *.iws 18 | *.iml 19 | *.ipr 20 | /out/ 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.4.RELEASE' 3 | id 'java' 4 | } 5 | 6 | apply plugin: 'io.spring.dependency-management' 7 | 8 | group = 'com.example' 9 | version = '1.0.0-SNAPSHOT' 10 | sourceCompatibility = '1.8' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' 18 | implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 19 | implementation 'org.springframework.boot:spring-boot-starter-webflux' 20 | runtimeOnly 'org.springframework.boot:spring-boot-devtools' 21 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 22 | } 23 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab3/library-client-credentials-initial/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'library-client-credentials-initial' 7 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/src/main/java/com/example/library/client/credentials/LibraryClientCredentialsInitialApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class LibraryClientCredentialsInitialApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(LibraryClientCredentialsInitialApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/src/main/java/com/example/library/client/credentials/config/WebClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.reactive.function.client.WebClient; 6 | 7 | @Configuration 8 | public class WebClientConfiguration { 9 | 10 | @Bean 11 | WebClient webClient() { 12 | return WebClient.builder().build(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/src/main/java/com/example/library/client/credentials/config/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; 5 | import org.springframework.security.config.web.server.ServerHttpSecurity; 6 | import org.springframework.security.web.server.SecurityWebFilterChain; 7 | 8 | @EnableWebFluxSecurity 9 | public class WebSecurityConfig { 10 | 11 | @Bean 12 | public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { 13 | http.authorizeExchange() 14 | .anyExchange() 15 | .permitAll() 16 | .and() 17 | .httpBasic() 18 | .disable() 19 | .formLogin() 20 | .disable(); 21 | return http.build(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/src/main/java/com/example/library/client/credentials/web/BookListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials.web; 2 | 3 | import java.util.Collection; 4 | 5 | public class BookListResource { 6 | 7 | private Collection books; 8 | 9 | public BookListResource() {} 10 | 11 | public BookListResource(Collection books) { 12 | this.books = books; 13 | } 14 | 15 | public Collection getBooks() { 16 | return books; 17 | } 18 | 19 | public void setBooks(Collection books) { 20 | this.books = books; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/src/main/java/com/example/library/client/credentials/web/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials.web; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | 9 | @ControllerAdvice 10 | public class ErrorHandler { 11 | 12 | @ExceptionHandler(AccessDeniedException.class) 13 | public ResponseEntity handle(AccessDeniedException ex) { 14 | return ResponseEntity.status(HttpStatus.FORBIDDEN) 15 | .body("You are not authorized to access this resource"); 16 | } 17 | 18 | @ExceptionHandler(IllegalArgumentException.class) 19 | public ResponseEntity handle(IllegalArgumentException ex) { 20 | return ResponseEntity.badRequest().body(ex.getMessage()); 21 | } 22 | 23 | @ExceptionHandler(Exception.class) 24 | public ResponseEntity handle(Exception ex) { 25 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9092 3 | error: 4 | include-stacktrace: never 5 | 6 | spring: 7 | thymeleaf: 8 | cache: false 9 | security: 10 | user: 11 | password: secret 12 | 13 | logging: 14 | level: 15 | root: info 16 | org: 17 | springframework: 18 | web: info 19 | 20 | library: 21 | server: http://localhost:9091/library-server 22 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library Client 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |

Library Client

13 |

Client Credentials Flow

14 | 15 |
16 |

An error occurred

17 | 18 |
    19 |
  • 20 |
  • 21 |
22 | 23 | Home 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /lab3/library-client-credentials-initial/src/test/java/com/example/library/client/credentials/LibraryClientCredentialsInitialApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.library.client.credentials; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class LibraryClientCredentialsInitialApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() {} 14 | } 15 | -------------------------------------------------------------------------------- /lab4/jwt-generator/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | /build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | 6 | ### STS ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | *.iws 18 | *.iml 19 | *.ipr 20 | /out/ 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | -------------------------------------------------------------------------------- /lab4/jwt-generator/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.4.RELEASE' 3 | id 'java' 4 | } 5 | 6 | apply plugin: 'io.spring.dependency-management' 7 | 8 | group = 'com.example' 9 | version = '1.0.0-SNAPSHOT' 10 | sourceCompatibility = '1.8' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 18 | implementation 'org.springframework.boot:spring-boot-starter-web' 19 | implementation 'com.nimbusds:nimbus-jose-jwt:7.0.1' 20 | implementation 'org.apache.commons:commons-lang3' 21 | runtimeOnly 'org.springframework.boot:spring-boot-devtools' 22 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 23 | } 24 | -------------------------------------------------------------------------------- /lab4/jwt-generator/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab4/jwt-generator/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lab4/jwt-generator/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lab4/jwt-generator/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url 'https://repo.spring.io/snapshot' } 4 | maven { url 'https://repo.spring.io/milestone' } 5 | gradlePluginPortal() 6 | } 7 | resolutionStrategy { 8 | eachPlugin { 9 | if (requested.id.id == 'org.springframework.boot') { 10 | useModule("org.springframework.boot:spring-boot-gradle-plugin:${requested.version}") 11 | } 12 | } 13 | } 14 | } 15 | rootProject.name = 'lab4-jwt-generator' 16 | -------------------------------------------------------------------------------- /lab4/jwt-generator/src/main/java/com/example/jwt/generator/JwtGeneratorApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.jwt.generator; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JwtGeneratorApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JwtGeneratorApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab4/jwt-generator/src/main/java/com/example/jwt/generator/User.java: -------------------------------------------------------------------------------- 1 | package com.example.jwt.generator; 2 | 3 | public class User { 4 | 5 | private String username; 6 | private String firstName; 7 | private String lastName; 8 | private String email; 9 | private String role; 10 | 11 | public String getUsername() { 12 | return username; 13 | } 14 | 15 | public void setUsername(String username) { 16 | this.username = username; 17 | } 18 | 19 | public String getFirstName() { 20 | return firstName; 21 | } 22 | 23 | public void setFirstName(String firstName) { 24 | this.firstName = firstName; 25 | } 26 | 27 | public String getLastName() { 28 | return lastName; 29 | } 30 | 31 | public void setLastName(String lastName) { 32 | this.lastName = lastName; 33 | } 34 | 35 | public String getEmail() { 36 | return email; 37 | } 38 | 39 | public void setEmail(String email) { 40 | this.email = email; 41 | } 42 | 43 | public String getRole() { 44 | return role; 45 | } 46 | 47 | public void setRole(String role) { 48 | this.role = role; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lab4/jwt-generator/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9093 3 | -------------------------------------------------------------------------------- /lab4/jwt-generator/src/main/resources/jwt_keys.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab4/jwt-generator/src/main/resources/jwt_keys.jks -------------------------------------------------------------------------------- /lab4/jwt-generator/src/main/resources/templates/result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library Server JWt Generator 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |

Library Server JWt Generator

13 | 14 |
15 | 16 |

JSON Web Token (JWT)

17 | 18 |

19 | 20 |

You may use this token now as bearer header

21 |

22 | 23 |
24 | 25 | Home 26 | 27 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /lab4/jwt-generator/src/test/java/com/example/jwt/generator/JwtGeneratorApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.jwt.generator; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class JwtGeneratorApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() {} 14 | } 15 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /build/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | bin/ -------------------------------------------------------------------------------- /lab4/library-server-static-complete/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/lab4/library-server-static-complete/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lab4/library-server-static-complete/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url 'https://repo.spring.io/snapshot' } 4 | maven { url 'https://repo.spring.io/milestone' } 5 | gradlePluginPortal() 6 | } 7 | resolutionStrategy { 8 | eachPlugin { 9 | if (requested.id.id == 'org.springframework.boot') { 10 | useModule("org.springframework.boot:spring-boot-gradle-plugin:${requested.version}") 11 | } 12 | } 13 | } 14 | } 15 | rootProject.name = 'library-server-static-complete' 16 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/CompleteStaticLibraryServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CompleteStaticLibraryServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CompleteStaticLibraryServerApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/api/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.security.access.AccessDeniedException; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | 11 | @RestControllerAdvice 12 | public class ErrorHandler { 13 | 14 | @ExceptionHandler(RuntimeException.class) 15 | public ResponseEntity handle(RuntimeException ex) { 16 | Logger logger = LoggerFactory.getLogger(this.getClass()); 17 | logger.error(ex.getMessage(), ex); 18 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); 19 | } 20 | 21 | @ExceptionHandler(Exception.class) 22 | public ResponseEntity handle(Exception ex) { 23 | Logger logger = LoggerFactory.getLogger(this.getClass()); 24 | logger.error(ex.getMessage(), ex); 25 | return ResponseEntity.badRequest().body(ex.getMessage()); 26 | } 27 | 28 | @ExceptionHandler(AccessDeniedException.class) 29 | public ResponseEntity handle(AccessDeniedException ex) { 30 | Logger logger = LoggerFactory.getLogger(this.getClass()); 31 | logger.error(ex.getMessage(), ex); 32 | return ResponseEntity.status(HttpStatus.FORBIDDEN) 33 | .body("User is not authorized to use this resource"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/api/resource/BookListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import java.util.Collection; 4 | 5 | public class BookListResource { 6 | 7 | private final Collection books; 8 | 9 | public BookListResource(Collection books) { 10 | this.books = books; 11 | } 12 | 13 | public Collection getBooks() { 14 | return books; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/api/resource/ModifyingUserResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import com.example.library.server.common.Role; 4 | 5 | import javax.validation.constraints.NotNull; 6 | import javax.validation.constraints.Pattern; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.UUID; 10 | 11 | public class ModifyingUserResource extends UserResource { 12 | 13 | @NotNull 14 | @Pattern(regexp = "[A-Za-z0-9_!]{8,100}") 15 | private String password; 16 | 17 | private List roles = new ArrayList<>(); 18 | 19 | public ModifyingUserResource() {} 20 | 21 | public ModifyingUserResource( 22 | UUID identifier, 23 | String email, 24 | String firstName, 25 | String lastName, 26 | String password, 27 | List roles) { 28 | super(identifier, email, firstName, lastName); 29 | this.password = password; 30 | this.roles = roles; 31 | } 32 | 33 | public String getPassword() { 34 | return password; 35 | } 36 | 37 | public void setPassword(String password) { 38 | this.password = password; 39 | } 40 | 41 | public List getRoles() { 42 | return roles; 43 | } 44 | 45 | public void setRoles(List roles) { 46 | this.roles = roles; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/api/resource/UserListResource.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.api.resource; 2 | 3 | import java.util.Collection; 4 | 5 | public class UserListResource { 6 | 7 | private final Collection users; 8 | 9 | public UserListResource(Collection users) { 10 | this.users = users; 11 | } 12 | 13 | public Collection getUsers() { 14 | return users; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/common/Role.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.common; 2 | 3 | public enum Role { 4 | LIBRARY_USER, 5 | 6 | LIBRARY_CURATOR, 7 | 8 | LIBRARY_ADMIN 9 | } 10 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/config/IdGeneratorConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.util.IdGenerator; 6 | import org.springframework.util.JdkIdGenerator; 7 | 8 | @Configuration 9 | public class IdGeneratorConfiguration { 10 | 11 | @Bean 12 | public IdGenerator idGenerator() { 13 | return new JdkIdGenerator(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/dataaccess/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import org.springframework.data.jpa.repository.EntityGraph; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | 9 | public interface BookRepository extends JpaRepository { 10 | 11 | Optional findOneByIdentifier(UUID identifier); 12 | 13 | @EntityGraph(attributePaths = "borrowedBy") 14 | Optional findOneWithDetailsByIdentifier(UUID identifier); 15 | 16 | void deleteBookByIdentifier(UUID identifier); 17 | } 18 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/dataaccess/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import org.springframework.data.jpa.repository.EntityGraph; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | 9 | public interface UserRepository extends JpaRepository { 10 | 11 | @EntityGraph(attributePaths = "roles") 12 | Optional findOneByEmail(String email); 13 | 14 | Optional findOneByIdentifier(UUID identifier); 15 | 16 | void deleteUserByIdentifier(UUID identifier); 17 | } 18 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/security/AudienceValidator.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import org.springframework.security.oauth2.core.OAuth2Error; 4 | import org.springframework.security.oauth2.core.OAuth2TokenValidator; 5 | import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; 6 | import org.springframework.security.oauth2.jwt.Jwt; 7 | 8 | /** Validator for expected audience in access tokens. */ 9 | public class AudienceValidator implements OAuth2TokenValidator { 10 | 11 | private OAuth2Error error = 12 | new OAuth2Error("invalid_token", "The required audience 'library-service' is missing", null); 13 | 14 | public OAuth2TokenValidatorResult validate(Jwt jwt) { 15 | if (jwt.getAudience().contains("library-service")) { 16 | return OAuth2TokenValidatorResult.success(); 17 | } else { 18 | return OAuth2TokenValidatorResult.failure(error); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/security/LibraryUser.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import com.example.library.server.dataaccess.User; 4 | import org.springframework.security.core.GrantedAuthority; 5 | import org.springframework.security.core.authority.AuthorityUtils; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | 8 | import java.util.Collection; 9 | 10 | public class LibraryUser extends User implements UserDetails { 11 | 12 | public LibraryUser(User user) { 13 | super(user); 14 | } 15 | 16 | @Override 17 | public Collection getAuthorities() { 18 | return AuthorityUtils.createAuthorityList( 19 | getRoles().stream().map(r -> "ROLE_" + r).toArray(String[]::new)); 20 | } 21 | 22 | @Override 23 | public String getPassword() { 24 | return "n/a"; 25 | } 26 | 27 | @Override 28 | public String getUsername() { 29 | return getEmail(); 30 | } 31 | 32 | @Override 33 | public boolean isAccountNonExpired() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public boolean isAccountNonLocked() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public boolean isCredentialsNonExpired() { 44 | return true; 45 | } 46 | 47 | @Override 48 | public boolean isEnabled() { 49 | return true; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/security/LibraryUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import com.example.library.server.business.UserService; 4 | import org.springframework.security.core.userdetails.UserDetails; 5 | import org.springframework.security.core.userdetails.UserDetailsService; 6 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class LibraryUserDetailsService implements UserDetailsService { 11 | 12 | private final UserService userService; 13 | 14 | public LibraryUserDetailsService(UserService userService) { 15 | this.userService = userService; 16 | } 17 | 18 | @Override 19 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 20 | return userService 21 | .findOneByEmail(username) 22 | .map(LibraryUser::new) 23 | .orElseThrow( 24 | () -> new UsernameNotFoundException(String.format("No user found for %s", username))); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/security/LibraryUserRolesJwtAuthenticationConverter.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import org.springframework.core.convert.converter.Converter; 4 | import org.springframework.security.authentication.AbstractAuthenticationToken; 5 | import org.springframework.security.authentication.BadCredentialsException; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.oauth2.jwt.Jwt; 8 | 9 | import java.util.Optional; 10 | 11 | /** JWT converter that takes the roles from persistent user roles. */ 12 | @SuppressWarnings("unused") 13 | public class LibraryUserRolesJwtAuthenticationConverter 14 | implements Converter { 15 | 16 | private final LibraryUserDetailsService libraryUserDetailsService; 17 | 18 | public LibraryUserRolesJwtAuthenticationConverter( 19 | LibraryUserDetailsService libraryUserDetailsService) { 20 | this.libraryUserDetailsService = libraryUserDetailsService; 21 | } 22 | 23 | @Override 24 | public AbstractAuthenticationToken convert(Jwt jwt) { 25 | return Optional.ofNullable(libraryUserDetailsService.loadUserByUsername(jwt.getSubject())) 26 | .map(u -> new UsernamePasswordAuthenticationToken(u, "n/a", u.getAuthorities())) 27 | .orElseThrow(() -> new BadCredentialsException("User not found")); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/java/com/example/library/server/security/PreAuthorizeNotRequired.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.security; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Custom annotation without any function but just to document that no pre-authorization is required 12 | * here by intention. 13 | */ 14 | @Target({ElementType.METHOD, ElementType.TYPE}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Inherited 17 | @Documented 18 | public @interface PreAuthorizeNotRequired {} 19 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | management: 2 | endpoints: 3 | web: 4 | exposure: 5 | include: '*' 6 | endpoint: 7 | health: 8 | show-details: always 9 | spring: 10 | jpa: 11 | open-in-view: false 12 | jackson: 13 | date-format: com.fasterxml.jackson.databind.util.StdDateFormat 14 | default-property-inclusion: non_null 15 | security: 16 | oauth2: 17 | resourceserver: 18 | jwt: 19 | publicKeyLocation: classpath:library_server.pub 20 | 21 | logging: 22 | level: 23 | org: 24 | springframework: 25 | security: debug 26 | server: 27 | error: 28 | include-stacktrace: never 29 | port: 9091 30 | servlet: 31 | context-path: /library-server 32 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/main/resources/library_server.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzdLH1bjS6dyWQ9MpWy1h 3 | vngC5a5pV/iULYdA/WCOR9rrqTwzGBoyF+qVhItExlvJ15hjLfi0hBIEwMPME1I6 4 | b1C3S3B6WECC6AQnLkdl7ApcMnUSvEOYqYOQJRNqdoA30mfL109zoMF1etQ74Dz1 5 | lo7wIGTn3lWI9EzzFDgs7MLNvbuC7qR3FoHquDfpxcIojKlF6OZCnFLV1GuSTOZy 6 | HkIL0M5kifa/UfF1XoBKgfh7rdMSF2OYkrG9/10/9yYPU2tEkoGAGVp3FWzfLwaq 7 | iHEiKp+R7+XBRPUi55TsQ/8dW0f/ZpYisrqawdau5e9VidQVKQKW6ahqfh1NLL/Z 8 | NwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/test/java/com/example/library/server/dataaccess/BookBuilder.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public final class BookBuilder { 8 | 9 | private UUID identifier = UUID.randomUUID(); 10 | private String isbn = "978-123-456-789"; 11 | private String title = "A book title"; 12 | private String description = "A book description"; 13 | private List authors = new ArrayList<>(); 14 | private boolean borrowed = false; 15 | private User user = null; 16 | 17 | private BookBuilder() {} 18 | 19 | public static BookBuilder book() { 20 | return new BookBuilder(); 21 | } 22 | 23 | public BookBuilder withIdentifier(UUID identifier) { 24 | this.identifier = identifier; 25 | return this; 26 | } 27 | 28 | public BookBuilder withIsbn(String isbn) { 29 | this.isbn = isbn; 30 | return this; 31 | } 32 | 33 | public BookBuilder withTitle(String title) { 34 | this.title = title; 35 | return this; 36 | } 37 | 38 | public BookBuilder withDescription(String description) { 39 | this.description = description; 40 | return this; 41 | } 42 | 43 | public BookBuilder withAuthor(String author) { 44 | this.authors.add(author); 45 | return this; 46 | } 47 | 48 | public BookBuilder borrowWith(User user) { 49 | this.borrowed = true; 50 | this.user = user; 51 | return this; 52 | } 53 | 54 | public Book build() { 55 | return new Book(identifier, isbn, title, description, authors, borrowed, user); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lab4/library-server-static-complete/src/test/java/com/example/library/server/dataaccess/UserBuilder.java: -------------------------------------------------------------------------------- 1 | package com.example.library.server.dataaccess; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public final class UserBuilder { 8 | 9 | private UUID identifier = UUID.randomUUID(); 10 | 11 | private String email = "first.last@example.com"; 12 | 13 | private String firstName = "First"; 14 | 15 | private String lastName = "Last"; 16 | 17 | private List roles = new ArrayList<>(); 18 | 19 | private UserBuilder() {} 20 | 21 | public static UserBuilder user() { 22 | return new UserBuilder(); 23 | } 24 | 25 | public UserBuilder withIdentifier(UUID identifier) { 26 | this.identifier = identifier; 27 | return this; 28 | } 29 | 30 | public UserBuilder withEmail(String email) { 31 | this.email = email; 32 | return this; 33 | } 34 | 35 | public UserBuilder withFirstName(String firstName) { 36 | this.firstName = firstName; 37 | return this; 38 | } 39 | 40 | public UserBuilder withLastName(String lastName) { 41 | this.lastName = lastName; 42 | return this; 43 | } 44 | 45 | public UserBuilder addRole(String role) { 46 | this.roles.add(role); 47 | return this; 48 | } 49 | 50 | public User build() { 51 | return new User(identifier, email, firstName, lastName, roles); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url 'https://repo.spring.io/snapshot' } 4 | maven { url 'https://repo.spring.io/milestone' } 5 | gradlePluginPortal() 6 | } 7 | resolutionStrategy { 8 | eachPlugin { 9 | if (requested.id.id == 'org.springframework.boot') { 10 | useModule("org.springframework.boot:spring-boot-gradle-plugin:${requested.version}") 11 | } 12 | } 13 | } 14 | } 15 | rootProject.name = 'oidc-workshop-spring-io-2019' 16 | 17 | include 'intro-labs:auth-code-demo' 18 | include 'intro-labs:github-client' 19 | include 'lab1:library-server-initial' 20 | include 'lab1:library-server-complete-automatic' 21 | include 'lab1:library-server-complete-custom' 22 | include 'lab2:library-client-initial' 23 | include 'lab2:library-client-complete' 24 | include 'lab3:library-client-credentials-initial' 25 | include 'lab3:library-client-credentials-complete' 26 | include 'lab4:jwt-generator' 27 | include 'lab4:library-server-static-complete' 28 | 29 | -------------------------------------------------------------------------------- /setup_keycloak/keycloak_data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/setup_keycloak/keycloak_data.zip -------------------------------------------------------------------------------- /setup_keycloak/keycloak_workshop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andifalk/oidc-workshop-spring-io-2019/cf9584940940cc1fa429a68af590cbede162512b/setup_keycloak/keycloak_workshop.png --------------------------------------------------------------------------------