You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/04/09 11:18:55 UTC

[isis] 02/04: ISIS-2484: adds docs on how to set up spring oauth2

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch 2.0.0-M5
in repository https://gitbox.apache.org/repos/asf/isis.git

commit c6117454ea311051c30dba3b2eaf9cf6ad056058
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 9 10:42:54 2021 +0100

    ISIS-2484: adds docs on how to set up spring oauth2
---
 .../modules/spring/images/github-client-id.png     | Bin 0 -> 508338 bytes
 .../spring/images/register-github-oauth-app.png    | Bin 0 -> 308822 bytes
 .../src/main/adoc/modules/spring/pages/about.adoc  | 223 ++++++++++++++++++++-
 3 files changed, 217 insertions(+), 6 deletions(-)

diff --git a/security/spring/src/main/adoc/modules/spring/images/github-client-id.png b/security/spring/src/main/adoc/modules/spring/images/github-client-id.png
new file mode 100644
index 0000000..cc95a52
Binary files /dev/null and b/security/spring/src/main/adoc/modules/spring/images/github-client-id.png differ
diff --git a/security/spring/src/main/adoc/modules/spring/images/register-github-oauth-app.png b/security/spring/src/main/adoc/modules/spring/images/register-github-oauth-app.png
new file mode 100644
index 0000000..0a00075
Binary files /dev/null and b/security/spring/src/main/adoc/modules/spring/images/register-github-oauth-app.png differ
diff --git a/security/spring/src/main/adoc/modules/spring/pages/about.adoc b/security/spring/src/main/adoc/modules/spring/pages/about.adoc
index 66fa230..faeb3d5 100644
--- a/security/spring/src/main/adoc/modules/spring/pages/about.adoc
+++ b/security/spring/src/main/adoc/modules/spring/pages/about.adoc
@@ -1,16 +1,34 @@
-= Sring Security
+= Spring Security
 
 :Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
 :page-partial:
 
-WARNING: TODO: this content has not yet been reviewed/updated for v2.0
 
-This guide describes the configuration of the Spring implementation of Apache Isis' `Authenticator and `Authorizor` APIs.
+This guide describes the configuration of the Spring implementation of Apache Isis' xref:refguide:core:index/security/authentication/Authenticator.adoc[Authenticator] SPI.
 
+It does _not_ however provide any implementation of xref:refguide:core:index/security/authorization/Authorizor.adoc[Authorizor] SPI.
+You will therefore need to configure an alternative implementation, eg the xref:bypass:about.adoc[Bypass] implementation (to disable authorisation checks completely), or use the xref:secman:about.adoc[SecMan] implementation.
 
-include::docs:mavendeps:partial$setup-and-configure-mavendeps-webapp.adoc[leveloffset=+1]
 
+include::docs:mavendeps:partial$setup-and-configure-dependencyManagement.adoc[leveloffset=+1]
 
+
+== Dependency
+
+In the webapp module of your application, add the following dependency:
+
+[source,xml]
+.pom.xml
+----
+<dependencies>
+    <dependency>
+        <groupId>org.apache.isis.security</groupId>
+        <artifactId>isis-security-spring</artifactId>
+    </dependency>
+</dependencies>
+----
+
+[[_update-appmanifest]]
 == Update AppManifest
 
 In your application's `AppManifest` (top-level Spring `@Configuration` used to bootstrap the app), import the
@@ -68,7 +86,200 @@ if(springAuthentication==null
 For an authenticated user the `org.apache.isis.viewer.wicket.roles.USER` role -- as required by xref:vw::about.adoc[Web UI (Wicket viewer)]  -- is automatically added to the list of roles.
 
 
-== Walk-through
+== Walk-through : OAuth2
+
+Using Spring Security we can configure your app with various authentication providers.
+In this section we describe how to modify the xref:docs:starters:helloworld.adoc[HelloWorld] starter app to use github as an OAuth2 provider.
+The steps here are based on link:https://spring.io/guides/tutorials/spring-boot-oauth2/[this Spring tutorial].
+
+=== Code Changes
+
+First, we configure the necessary components:
+
+* add in OAuth2 client dependency:
++
+[source,xml]
+.pom.xml
+----
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-oauth2-client</artifactId>
+    <exclusions>
+        <exclusion>
+            <groupId>org.springframework.boot</groupId>           <!--.-->
+            <artifactId>spring-boot-starter-logging</artifactId>
+        </exclusion>
+    </exclusions>
+</dependency>
+----
+<.> excluded to avoid log4j2 <--> slf4j bidirectional dependency
+
+* in `AppManifest` (as described <<_update-appmanifest,above>>), import the `IsisModuleSecuritySpring` module
+
+* as this module provides no implementation of the xref:refguide:core:index/security/authorization/Authorizor.adoc[Authorizor] SPI, instead configure  an alternative implementation from the xref:bypass:about.adoc[Bypass] implementation (this will in effect disable authorisation checks):
++
+[source,java]
+.AppManifest.java
+----
+@Configuration
+@Import({
+        ...
+        AuthorizorBypass.class,
+        ...
+})
+public class AppManifest {
+}
+----
+
+The OAuth2 integration provided by Spring (seemingly) forwards onto an "/login" endpoint immediately after the user has logged into github, but with an authenticated principal.
+We therefore use a controller to simply forward directly onto the xref:vw::about.adoc[Wicket Viewer]:
+
+* create this page to redirect:
++
+[source,html]
+.templates/redirect-immediately.html
+----
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html xmlns:th="http://www.thymeleaf.org">
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <meta http-equiv="refresh" content="0;url=/wicket/" />
+    </head>
+    <body>
+        <div id="wrapper">
+        </div>
+    </body>
+</html>
+----
+
+* define this controller for `/login`:
++
+[source,java]
+.LoginController.java
+----
+@Controller
+@RequestMapping({"/login"})
+public class LoginController {
+
+    @RequestMapping(
+        produces = {"text/html"}
+    )
+    public String login(HttpServletRequest request, HttpServletResponse response) {
+        return "redirect-immediately";
+    }
+}
+----
+
+* register in `AppManifest`:
++
+[source,java]
+.AppManifest.java
+----
+@Configuration
+@Import({
+        ...
+        LoginController.class,
+        ...
+})
+public class AppManifest {
+}
+----
+
+
+=== Code Patch
+
+In the current release of Apache Isis ({page-rel}), there is an issue with its `SpringSecurityFilter`.
+We therefore (for now) need to patch in our own replacement.
+
+[source,java]
+.org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
+----
+package org.apache.isis.security.spring.webmodule;
+
+//...
+
+public class SpringSecurityFilter implements Filter {
+
+    @Autowired
+    private InteractionFactory isisInteractionFactory;
+
+    @Override
+    public void doFilter(
+            final ServletRequest servletRequest,
+            final ServletResponse servletResponse,
+            final FilterChain filterChain) throws IOException, ServletException {
+
+        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
+
+        org.springframework.security.core.Authentication springAuthentication = SecurityContextHolder.getContext().getAuthentication();
+        if(springAuthentication==null
+                || !springAuthentication.isAuthenticated()) {
+            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+            return; // not authenticated
+        }
+
+        String principalIdentity;
+
+        Object principal = springAuthentication.getPrincipal();
+        if (principal instanceof OAuth2User) {
+            OAuth2User oAuth2User = (OAuth2User) principal;
+            final Object login = oAuth2User.getAttributes().get("login");
+            principalIdentity = login instanceof String ? (String)login : oAuth2User.getName();
+        } else if (principal instanceof AuthenticatedPrincipal) {
+            AuthenticatedPrincipal authenticatedPrincipal = (AuthenticatedPrincipal) principal;
+            principalIdentity = authenticatedPrincipal.getName();
+        } else if (principal instanceof AbstractAuthenticationToken) {
+            final AbstractAuthenticationToken abstractAuthenticationToken = (AbstractAuthenticationToken) principal;
+            principalIdentity = abstractAuthenticationToken.getName();
+        } else if (principal instanceof String) {
+            principalIdentity = (String) principal;
+        } else {
+            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+            return; // unknown principal type, not handled
+        }
+
+
+        UserMemento user = UserMemento.ofNameAndRoleNames(principalIdentity,
+                Stream.of("org.apache.isis.viewer.wicket.roles.USER"));
+        SimpleAuthentication authentication = SimpleAuthentication.validOf(user);
+        authentication.setType(Authentication.Type.EXTERNAL);
+
+        isisInteractionFactory.runAuthenticated(
+                authentication,
+                ()->{
+                    filterChain.doFilter(servletRequest, servletResponse);
+                });
+    }
+}
+----
+
+Finally, (and optionally), the swagger/REST API is not configured for oauth2, so we replace the `index.html` page with one to redirect straight to the xref:vw::about.adoc[Wicket Viewer]:
+
+
+=== Configuration
+
+We are now ready to configure the app.
+As described in the link:https://spring.io/guides/tutorials/spring-boot-oauth2/[this Spring tutorial]:
+
+* register the app on github:
++
+image::register-github-oauth-app.png[]
+
+* obtain the clientId and create a new client secret:
++
+image::github-client-id.png[]
+
+* update the configuration:
++
+[source,properties]
+.application-github-example.properties
+----
+spring.security.oauth2.client.registration.github.clientId=XXXX
+spring.security.oauth2.client.registration.github.clientSecret=XXXXXXXX
+----
+
+=== Run the application
 
-WARNING: TODO - show how this fits together.
+You should now be able to run the application, selecting the "github-example" profile using this JVM argument:
 
+    -Dspring.profiles.active=github-example