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 09:01:41 UTC

[isis-app-helloworld] 01/01: adds example of oauth2 usage

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

danhaywood pushed a commit to branch jdo-oauth2
in repository https://gitbox.apache.org/repos/asf/isis-app-helloworld.git

commit e188475538b6fdfe71d07f037f11e30f6979cdee
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 9 10:01:17 2021 +0100

    adds example of oauth2 usage
---
 pom.xml                                            | 17 +++++
 src/main/java/domainapp/webapp/AppManifest.java    | 13 +++-
 .../java/domainapp/webapp/LoginController.java     | 20 ++++++
 .../spring/webmodule/SpringSecurityFilter.java     | 83 ++++++++++++++++++++++
 src/main/resources/config/.gitignore               |  1 +
 .../config/application-github-example.properties   |  2 +
 src/main/resources/static/index.html               | 62 +++-------------
 .../resources/templates/redirect-immediately.html  | 11 +++
 8 files changed, 156 insertions(+), 53 deletions(-)

diff --git a/pom.xml b/pom.xml
index 6fdb43c..6469e2c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,23 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.isis.security</groupId>
+            <artifactId>isis-security-spring</artifactId>
+        </dependency>
+
+        <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>
+
+        <dependency>
             <groupId>org.apache.isis.mavendeps</groupId>
             <artifactId>isis-mavendeps-jdo</artifactId>
             <type>pom</type>
diff --git a/src/main/java/domainapp/webapp/AppManifest.java b/src/main/java/domainapp/webapp/AppManifest.java
index 86995b9..76eafe1 100644
--- a/src/main/java/domainapp/webapp/AppManifest.java
+++ b/src/main/java/domainapp/webapp/AppManifest.java
@@ -4,11 +4,18 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 import org.springframework.context.annotation.PropertySource;
 import org.springframework.context.annotation.PropertySources;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
 
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.core.runtimeservices.IsisModuleCoreRuntimeServices;
 import org.apache.isis.persistence.jdo.datanucleus.IsisModuleJdoDatanucleus;
+import org.apache.isis.security.bypass.authorization.AuthorizorBypass;
 import org.apache.isis.security.shiro.IsisModuleSecurityShiro;
+import org.apache.isis.security.spring.IsisModuleSecuritySpring;
 import org.apache.isis.testing.h2console.ui.IsisModuleTestingH2ConsoleUi;
 import org.apache.isis.viewer.restfulobjects.jaxrsresteasy4.IsisModuleViewerRestfulObjectsJaxrsResteasy4;
 import org.apache.isis.viewer.wicket.viewer.IsisModuleViewerWicketViewer;
@@ -18,11 +25,14 @@ import domainapp.modules.hello.HelloWorldModule;
 @Configuration
 @Import({
         IsisModuleCoreRuntimeServices.class,
-        IsisModuleSecurityShiro.class,
+        IsisModuleSecuritySpring.class,
         IsisModuleJdoDatanucleus.class,
         IsisModuleViewerRestfulObjectsJaxrsResteasy4.class,
         IsisModuleViewerWicketViewer.class,
 
+        LoginController.class,
+        AuthorizorBypass.class,
+
         IsisModuleTestingH2ConsoleUi.class,
         HelloWorldModule.class
 })
@@ -30,4 +40,5 @@ import domainapp.modules.hello.HelloWorldModule;
     @PropertySource(IsisPresets.NoTranslations),
 })
 public class AppManifest {
+
 }
diff --git a/src/main/java/domainapp/webapp/LoginController.java b/src/main/java/domainapp/webapp/LoginController.java
new file mode 100644
index 0000000..9492549
--- /dev/null
+++ b/src/main/java/domainapp/webapp/LoginController.java
@@ -0,0 +1,20 @@
+package domainapp.webapp;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Controller
+@RequestMapping({"/login"})
+public class LoginController {
+
+    @RequestMapping(
+        produces = {"text/html"}
+    )
+    public String login(HttpServletRequest request, HttpServletResponse response) {
+        return "redirect-immediately";
+    }
+
+}
diff --git a/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java b/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
new file mode 100644
index 0000000..45f931f
--- /dev/null
+++ b/src/main/java/org/apache/isis/security/spring/webmodule/SpringSecurityFilter.java
@@ -0,0 +1,83 @@
+package org.apache.isis.security.spring.webmodule;
+
+import java.io.IOException;
+import java.util.stream.Stream;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.core.AuthenticatedPrincipal;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
+import org.springframework.security.oauth2.core.user.OAuth2User;
+
+import org.apache.isis.applib.services.user.UserMemento;
+import org.apache.isis.core.interaction.session.InteractionFactory;
+import org.apache.isis.core.security.authentication.Authentication;
+import org.apache.isis.core.security.authentication.standard.SimpleAuthentication;
+
+/**
+ * This is a patch to replace the version provided in 2.0.0-M5
+ */
+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);
+                });
+    }
+
+}
diff --git a/src/main/resources/config/.gitignore b/src/main/resources/config/.gitignore
new file mode 100644
index 0000000..0f71df6
--- /dev/null
+++ b/src/main/resources/config/.gitignore
@@ -0,0 +1 @@
+application-github.properties
diff --git a/src/main/resources/config/application-github-example.properties b/src/main/resources/config/application-github-example.properties
new file mode 100644
index 0000000..a751715
--- /dev/null
+++ b/src/main/resources/config/application-github-example.properties
@@ -0,0 +1,2 @@
+spring.security.oauth2.client.registration.github.clientId=XXXXXXXXXXXXXXXXXXXX
+spring.security.oauth2.client.registration.github.clientSecret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html
index ec5144e..17b54b1 100644
--- a/src/main/resources/static/index.html
+++ b/src/main/resources/static/index.html
@@ -1,54 +1,12 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-    <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-        <title>Apache Isis&trade; HelloWorld</title>
-
-        <link rel="stylesheet" type="text/css" href="css/page.css">
-    </head>
-    <body>
-        <div id="wrapper">
-            <img alt="Isis Logo" src="images/apache-isis/logo.png" />
-
-            <p>
-                This is a minimal <a href="https://isis.apache.org">Apache Isis</a> application, intended as a starting
-                point to learn what the framework is all about.
-                <br/>
-            </p>
-
-            <p>To access the app:</p>
-            <ul>
-                <li>
-                    <p>
-                        <b><a href="wicket/">Generic UI (Wicket)</a></b>
-                    </p>
-                    <p>
-                        provides access to a generic UI for end-users.  This
-                        viewer is built with <a href="http://wicket.apache.org" target="_blank">Apache Wicket</a>&trade;.
-                    </p>
-                </li>
-                <li>
-                    <p>
-                        <b>
-                            <a href="swagger-ui/index.thtml">RESTful API (Swagger)</a>
-                        </b>
-                    </p>
-                    <p>
-                        provides access to a Swagger UI for convenient access
-                        to (a subset of) the automatically generated REST API.
-                    </p>
-                    <p>
-                        The full backend API (at <a href="restful/">restful/</a>) renders both simple and also richer
-                        hypermedia representations of domain objects, the latter conforming to the
-                        <a href="http://restfulobjects.org"  target="_blank">Restful Objects</a> spec.
-                    </p>
-                </li>
-            </ul>
-
-            <p>
-            The default user/password is <b><i>sven/pass</i></b>.
-            </p>
-
-        </div>
-    </body>
+<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">
+    <!-- we just redirect immediately, because swagger/restful API not configured to use oauth2 -->
+</div>
+</body>
 </html>
diff --git a/src/main/resources/templates/redirect-immediately.html b/src/main/resources/templates/redirect-immediately.html
new file mode 100644
index 0000000..fd1f326
--- /dev/null
+++ b/src/main/resources/templates/redirect-immediately.html
@@ -0,0 +1,11 @@
+<!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>