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

ahuber pushed a commit to branch jpa3-SNAPSHOT
in repository https://gitbox.apache.org/repos/asf/causeway-app-helloworld.git

commit 8067a41e4da743d2df7569e9dd07b0b5f47f0bab
Author: Andi Huber <[email protected]>
AuthorDate: Wed Mar 20 15:18:53 2024 +0100

    use SimpleAuth as Shiro replacement
---
 pom.xml                                            |  11 +--
 .../modules/hello/dom/hwo/HelloWorldObject.java    |  28 +++---
 .../modules/hello/dom/hwo/HelloWorldObjects.java   |   6 +-
 src/main/java/domainapp/webapp/AppManifest.java    |   3 +-
 src/main/java/domainapp/webapp/HelloWorldApp.java  |  51 +++++++++-
 src/main/java/domainapp/webapp/SimpleAuth.java     | 106 +++++++++++++++++++++
 src/main/resources/shiro.ini                       |  49 ----------
 7 files changed, 179 insertions(+), 75 deletions(-)

diff --git a/pom.xml b/pom.xml
index cad7745..51818b9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,20 +7,19 @@
     <parent>
         <groupId>org.apache.causeway.app</groupId>
         <artifactId>causeway-app-starter-parent</artifactId>
-        <version>2.0.0-SNAPSHOT</version>
+        <version>3.0.0-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
     <artifactId>helloworld-jpa</artifactId>
     <groupId>org.apache.causeway.starters</groupId>
-    <version>2.0.0-SNAPSHOT</version>
 
     <name>HelloWorld (JPA)</name>
 
     <packaging>jar</packaging>
 
     <properties>
-        <java.version>11</java.version>
+        <java.version>21</java.version>
                <!-- 
https://stackoverflow.com/questions/38983934/cannot-get-maven-project-version-property-in-a-spring-application-with-value/38983935#38983935
 -->
                <resource.delimiter>^</resource.delimiter>
     </properties>
@@ -88,7 +87,7 @@
 
         <dependency>
             <groupId>org.apache.causeway.security</groupId>
-            <artifactId>causeway-security-shiro</artifactId>
+            <artifactId>causeway-security-bypass</artifactId>
         </dependency>
 
         <dependency>
@@ -115,7 +114,7 @@
             <groupId>org.springframework</groupId>
             <artifactId>spring-instrument</artifactId>
         </dependency>
-
+        
     </dependencies>
 
     <profiles>
@@ -133,7 +132,7 @@
                         <artifactId>jib-maven-plugin</artifactId>
                         <configuration>
                             <from>
-                                
<image>adoptopenjdk/openjdk11:x86_64-alpine-jre-11.0.10_9</image>
+                                <image>openjdk:21-jdk-bookworm</image>
                             </from>
                             <container>
                                 <jvmFlags>
diff --git 
a/src/main/java/domainapp/modules/hello/dom/hwo/HelloWorldObject.java 
b/src/main/java/domainapp/modules/hello/dom/hwo/HelloWorldObject.java
index b93ae56..2d96194 100644
--- a/src/main/java/domainapp/modules/hello/dom/hwo/HelloWorldObject.java
+++ b/src/main/java/domainapp/modules/hello/dom/hwo/HelloWorldObject.java
@@ -2,18 +2,18 @@ package domainapp.modules.hello.dom.hwo;
 
 import java.util.Comparator;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.EntityListeners;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.Table;
-import javax.persistence.Transient;
-import javax.persistence.UniqueConstraint;
-import javax.persistence.Version;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EntityListeners;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import jakarta.persistence.Transient;
+import jakarta.persistence.UniqueConstraint;
+import jakarta.persistence.Version;
 
 import org.apache.causeway.applib.annotation.Action;
 import org.apache.causeway.applib.annotation.ActionLayout;
@@ -73,7 +73,7 @@ public class HelloWorldObject implements 
Comparable<HelloWorldObject> {
     public String getName() {
         return name;
     }
-    public void setName(String name) {
+    public void setName(final String name) {
         this.name = name;
     }
 
@@ -86,7 +86,7 @@ public class HelloWorldObject implements 
Comparable<HelloWorldObject> {
     public String getNotes() {
         return notes;
     }
-    public void setNotes(String notes) {
+    public void setNotes(final String notes) {
         this.notes = notes;
     }
 
diff --git 
a/src/main/java/domainapp/modules/hello/dom/hwo/HelloWorldObjects.java 
b/src/main/java/domainapp/modules/hello/dom/hwo/HelloWorldObjects.java
index b155532..8e2bc7e 100644
--- a/src/main/java/domainapp/modules/hello/dom/hwo/HelloWorldObjects.java
+++ b/src/main/java/domainapp/modules/hello/dom/hwo/HelloWorldObjects.java
@@ -2,9 +2,9 @@ package domainapp.modules.hello.dom.hwo;
 
 import java.util.List;
 
-import javax.annotation.Priority;
-import javax.inject.Inject;
-import javax.inject.Named;
+import jakarta.annotation.Priority;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
 
 import org.apache.causeway.applib.annotation.Action;
 import org.apache.causeway.applib.annotation.ActionLayout;
diff --git a/src/main/java/domainapp/webapp/AppManifest.java 
b/src/main/java/domainapp/webapp/AppManifest.java
index 1ad5341..0e5fb3a 100644
--- a/src/main/java/domainapp/webapp/AppManifest.java
+++ b/src/main/java/domainapp/webapp/AppManifest.java
@@ -10,7 +10,6 @@ import org.apache.causeway.applib.CausewayModuleApplibMixins;
 import org.apache.causeway.core.config.presets.CausewayPresets;
 import 
org.apache.causeway.core.runtimeservices.CausewayModuleCoreRuntimeServices;
 import 
org.apache.causeway.persistence.jpa.eclipselink.CausewayModulePersistenceJpaEclipselink;
-import org.apache.causeway.security.shiro.CausewayModuleSecurityShiro;
 import 
org.apache.causeway.testing.h2console.ui.CausewayModuleTestingH2ConsoleUi;
 import 
org.apache.causeway.viewer.restfulobjects.jaxrsresteasy.CausewayModuleViewerRestfulObjectsJaxrsResteasy;
 import 
org.apache.causeway.viewer.wicket.applib.CausewayModuleViewerWicketApplibMixins;
@@ -24,7 +23,7 @@ import domainapp.modules.hello.HelloWorldModule;
         CausewayModuleApplibChangeAndExecutionLoggers.class,
 
         CausewayModuleCoreRuntimeServices.class,
-        CausewayModuleSecurityShiro.class,
+        //CausewayModuleSecurityXxx.class,
         CausewayModulePersistenceJpaEclipselink.class,
         CausewayModuleViewerRestfulObjectsJaxrsResteasy.class,
         CausewayModuleViewerWicketApplibMixins.class,
diff --git a/src/main/java/domainapp/webapp/HelloWorldApp.java 
b/src/main/java/domainapp/webapp/HelloWorldApp.java
index 9ad441f..a67f5fa 100644
--- a/src/main/java/domainapp/webapp/HelloWorldApp.java
+++ b/src/main/java/domainapp/webapp/HelloWorldApp.java
@@ -1,19 +1,68 @@
 package domainapp.webapp;
 
+import java.util.List;
+
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import 
org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
 import org.apache.causeway.core.config.presets.CausewayPresets;
 
+import domainapp.webapp.HelloWorldApp.SimpleAuthSetup;
+import domainapp.webapp.SimpleAuth.Realm;
+
 @SpringBootApplication
 @Import({
+    SimpleAuthSetup.class,
+    SimpleAuth.class,
     AppManifest.class,
 })
 public class HelloWorldApp extends SpringBootServletInitializer {
 
-    public static void main(String[] args) {
+    @Configuration
+    static class SimpleAuthSetup {
+
+        /* migrated from shiro.ini
+            [users]
+            sven = pass, admin_role
+            dick = pass, hello_role, default_role
+            bob  = pass, hello_role, default_role, fixtures_role
+            joe  = pass, hello_role, default_role
+
+            [roles]
+            hello_role =   *:HelloWorldObjects:*:*,\
+                           *:HelloWorldObject:*:*
+            admin_role = *
+            default_role   = causeway.applib,\
+                             causeway.security
+            fixtures_role  = causeway.testing.fixtures
+            features_role  = causeway.feat
+            metamodel_role = causeway.metamodel
+            h2_role        = causeway.ext.h2Console
+            jdo_role       = causeway.persistence.jdo
+            swagger_role   = causeway.viewer.restfulobjects
+            conf_role      = causeway.conf
+            sudo_role      = causeway.sudo
+         */
+        @Bean
+        public SimpleAuth.Realm simpleAuthRealm() {
+            return new Realm()
+                .addRole("hello_role", 
id->id.getFullIdentityString().contains("HelloWorldObject"))
+                .addRole("admin_role", id->true)
+                .addRole("default_role", 
id->id.getFullIdentityString().startsWith("causeway.applib")
+                        || 
id.getFullIdentityString().startsWith("causeway.security"))
+                .addRole("fixtures_role", 
id->id.getFullIdentityString().startsWith("causeway..testing.fixtures"))
+                .addUser("sven", "pass", List.of("admin_role"))
+                .addUser("dick", "pass", List.of("hello_role", "default_role"))
+                .addUser("bob", "pass", List.of("hello_role", "default_role", 
"fixtures_role"))
+                .addUser("joe", "pass", List.of("hello_role", "default_role"));
+        }
+    }
+
+    public static void main(final String[] args) {
         CausewayPresets.prototyping(); // or run with use -DPROTOTYPING=true
         SpringApplication.run(new Class[] { HelloWorldApp.class }, args);
     }
diff --git a/src/main/java/domainapp/webapp/SimpleAuth.java 
b/src/main/java/domainapp/webapp/SimpleAuth.java
new file mode 100644
index 0000000..dd52a4a
--- /dev/null
+++ b/src/main/java/domainapp/webapp/SimpleAuth.java
@@ -0,0 +1,106 @@
+package domainapp.webapp;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import jakarta.inject.Inject;
+
+import org.springframework.stereotype.Component;
+
+import org.apache.causeway.applib.Identifier;
+import org.apache.causeway.applib.services.iactnlayer.InteractionContext;
+import org.apache.causeway.applib.services.user.UserMemento;
+import org.apache.causeway.core.security.authentication.AuthenticationRequest;
+import 
org.apache.causeway.core.security.authentication.AuthenticationRequestPassword;
+import org.apache.causeway.core.security.authentication.Authenticator;
+import org.apache.causeway.core.security.authorization.Authorizor;
+
+@Component
+public class SimpleAuth implements Authenticator, Authorizor {
+
+    static class Realm {
+        static record Role(String name, Predicate<Identifier> grantsRead, 
Predicate<Identifier> grantsChange) {
+        }
+        static record User(String name, String pass, List<Role> roles) {
+        }
+        final Map<String, Role> roles = new HashMap<>();
+        final Map<String, User> users = new HashMap<>();
+        public Realm addRole(final String name, final Predicate<Identifier> 
grants) {
+            roles.put(name, new Role(name, grants, grants));
+            return this;
+        }
+        public Realm addUser(final String name, final String pass, final 
List<String> roleNames) {
+            users.put(name, new User(name, pass, 
roleNames.stream().map(roles::get).toList()));
+            return this;
+        }
+    }
+
+    @Inject Realm realm;
+
+    /**
+     * Default implementation returns a validated {@link InteractionContext}; 
can be overridden
+     * if required.
+     */
+    @Override
+    public final InteractionContext authenticate(
+            final AuthenticationRequest request,
+            final String validationCode) {
+
+        if(request instanceof AuthenticationRequestPassword pwdRequest) {
+            if (!isValid(pwdRequest)) {
+                return null;
+            }
+        }
+
+        var user = UserMemento.ofNameAndRoleNames(request.getName(), 
Stream.concat(
+                    request.streamRoles(),
+                    realm.users.get(request.getName())
+                        .roles()
+                        .stream()
+                        .map(Realm.Role::name))
+                )
+                .withAuthenticationCode(validationCode);
+        return InteractionContext.ofUserWithSystemDefaults(user);
+    }
+
+    @Override
+    public final void logout() {
+        // no-op
+    }
+
+    @Override
+    public boolean isVisible(final InteractionContext ctx, final Identifier 
identifier) {
+        return roles(ctx.getUser()).stream()
+            .anyMatch(role->role.grantsRead().test(identifier));
+    }
+
+    @Override
+    public boolean isUsable(final InteractionContext ctx, final Identifier 
identifier) {
+        return roles(ctx.getUser()).stream()
+                .anyMatch(role->role.grantsChange().test(identifier));
+    }
+
+    @Override
+    public final boolean canAuthenticate(final Class<? extends 
AuthenticationRequest> authenticationRequestClass) {
+        return 
AuthenticationRequestPassword.class.isAssignableFrom(authenticationRequestClass);
+    }
+
+    protected boolean isValid(final AuthenticationRequestPassword request) {
+        return Optional.ofNullable(realm.users.get(request.getName()))
+            .map(Realm.User::pass)
+            .map(pass->pass.equals(request.getPassword()))
+            .orElse(false);
+    }
+
+    protected List<Realm.Role> roles(final UserMemento userMemento){
+        var roles = Optional.ofNullable(realm.users.get(userMemento.getName()))
+                .map(Realm.User::roles)
+                .orElseGet(List::of);
+        return roles;
+    }
+
+}
diff --git a/src/main/resources/shiro.ini b/src/main/resources/shiro.ini
deleted file mode 100644
index 30faa89..0000000
--- a/src/main/resources/shiro.ini
+++ /dev/null
@@ -1,49 +0,0 @@
-[main]
-
-# to use .ini file
-securityManager.realms = $iniRealm
-
-
-
-# -----------------------------------------------------------------------------
-# Users and their assigned roles
-#
-# Each line conforms to the format defined in the
-# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
-# -----------------------------------------------------------------------------
-
-[users]
-# user = password, role1, role2, role3, ...
-
-
-sven = pass, admin_role
-dick = pass, hello_role, default_role
-bob  = pass, hello_role, default_role, fixtures_role
-joe  = pass, hello_role, default_role
-
-
-
-# -----------------------------------------------------------------------------
-# Roles with assigned permissions
-#
-# Each line conforms to the format defined in the
-# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
-# -----------------------------------------------------------------------------
-
-[roles]
-# role = perm1, perm2, perm3, ...
-# perm in format: logicalTypeNamespace:logicalTypeSimpleName:memberName:r,w
-
-hello_role =   *:HelloWorldObjects:*:*,\
-               *:HelloWorldObject:*:*
-admin_role = *
-default_role   = causeway.applib,\
-                 causeway.security
-fixtures_role  = causeway.testing.fixtures
-features_role  = causeway.feat
-metamodel_role = causeway.metamodel
-h2_role        = causeway.ext.h2Console
-jdo_role       = causeway.persistence.jdo
-swagger_role   = causeway.viewer.restfulobjects
-conf_role      = causeway.conf
-sudo_role      = causeway.sudo

Reply via email to