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

ahuber pushed a commit to branch spring6
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit 08c1ab98a5993ccffc7ecee54defefe713a04cb1
Merge: 60b5631e42 59ec164562
Author: Andi Huber <[email protected]>
AuthorDate: Thu Mar 21 12:16:37 2024 +0100

    Merge remote-tracking branch 'origin/master' into spring6

 core/pom.xml                                       |   1 +
 security/simple/pom.xml                            |  62 ++++++++
 security/simple/src/main/adoc/antora.yml           |  19 +++
 .../simple/src/main/adoc/modules/simple/nav.adoc   |   4 +
 .../src/main/adoc/modules/simple/pages/about.adoc  |  55 +++++++
 .../adoc/modules/simple/partials/module-nav.adoc   |   5 +
 security/simple/src/main/java/module-info.java     |  33 ++++
 .../simple/CausewayModuleSecuritySimple.java       |  47 ++++++
 .../simple/authentication/SimpleAuthenticator.java | 104 +++++++++++++
 .../simple/authorization/SimpleAuthorizor.java     |  72 +++++++++
 .../security/simple/realm/SimpleRealm.java         |  79 ++++++++++
 .../security/simple/SecuritySimpleAuthTest.java    | 168 +++++++++++++++++++++
 12 files changed, 649 insertions(+)

diff --cc core/pom.xml
index 2cc66fb16f,0c6752308d..53c3252bcc
--- a/core/pom.xml
+++ b/core/pom.xml
@@@ -300,7 -300,8 +300,8 @@@
                <module>security</module>
                <module>../security/bypass</module>
                <module>../security/keycloak</module>
 -              <module>../security/shiro</module>
 -              <module>../security/simple</module>
 +<!--          <module>../security/shiro</module> Shiro 2.0.0 has no jakarta 
namespaces, exclude from build -->
++        <module>../security/simple</module>
                <module>../security/spring</module>
  
                <module>../viewers/commons</module>
diff --cc security/simple/pom.xml
index 0000000000,7ef64e7ee2..1d4192bdcb
mode 000000,100644..100644
--- a/security/simple/pom.xml
+++ b/security/simple/pom.xml
@@@ -1,0 -1,62 +1,62 @@@
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!--
+   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 agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ -->
+ <project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+       <modelVersion>4.0.0</modelVersion>
+ 
+     <parent>
+         <groupId>org.apache.causeway.core</groupId>
+         <artifactId>causeway-core</artifactId>
 -        <version>2.0.0-SNAPSHOT</version>
++        <version>3.0.0-SNAPSHOT</version>
+         <relativePath>../../core/pom.xml</relativePath>
+     </parent>
+ 
+     <groupId>org.apache.causeway.security</groupId>
+     <artifactId>causeway-security-simple</artifactId>
+     <name>Apache Causeway Security - Simple</name>
+ 
+     <properties>
+         
<jar-plugin.automaticModuleName>org.apache.causeway.security.simple</jar-plugin.automaticModuleName>
+         
<git-plugin.propertiesDir>org/apache/causeway/security/simple</git-plugin.propertiesDir>
+     </properties>
+ 
+     <dependencies>
+ 
+         <dependency>
+             <groupId>org.apache.causeway.core</groupId>
+             <artifactId>causeway-core-runtimeservices</artifactId>
+         </dependency>
+         
+         <dependency>
+                   <groupId>org.springframework.security</groupId>
+                   <artifactId>spring-security-crypto</artifactId>
+               </dependency>
+               
+               <!-- TESTING -->
+ 
+         <dependency>
+             <groupId>org.apache.causeway.core</groupId>
+             <artifactId>causeway-core-internaltestsupport</artifactId>
+             <scope>test</scope>
+         </dependency>
+         
+     </dependencies>
+ 
+ 
+ </project>
diff --cc security/simple/src/main/java/module-info.java
index 0000000000,6138361e5d..ceb8f42c39
mode 000000,100644..100644
--- a/security/simple/src/main/java/module-info.java
+++ b/security/simple/src/main/java/module-info.java
@@@ -1,0 -1,33 +1,33 @@@
+ /*
+  *  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 agreed to in writing,
+  *  software distributed under the License is distributed on an
+  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  *  KIND, either express or implied.  See the License for the
+  *  specific language governing permissions and limitations
+  *  under the License.
+  */
+ module org.apache.causeway.security.simple {
+     exports org.apache.causeway.security.simple;
+     exports org.apache.causeway.security.simple.authentication;
+     exports org.apache.causeway.security.simple.authorization;
+     exports org.apache.causeway.security.simple.realm;
+ 
+     requires org.apache.causeway.applib;
+     requires org.apache.causeway.security.api;
+     requires org.apache.causeway.core.runtimeservices;
 -    requires java.annotation;
 -    requires java.inject;
++    requires jakarta.annotation;
++    requires jakarta.inject;
+     requires spring.beans;
+     requires spring.context;
+     requires spring.security.crypto;
+ }
diff --cc 
security/simple/src/main/java/org/apache/causeway/security/simple/authentication/SimpleAuthenticator.java
index 0000000000,1fde1a8bcc..714dbb2159
mode 000000,100644..100644
--- 
a/security/simple/src/main/java/org/apache/causeway/security/simple/authentication/SimpleAuthenticator.java
+++ 
b/security/simple/src/main/java/org/apache/causeway/security/simple/authentication/SimpleAuthenticator.java
@@@ -1,0 -1,104 +1,104 @@@
+ /*
+  *  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 agreed to in writing,
+  *  software distributed under the License is distributed on an
+  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  *  KIND, either express or implied.  See the License for the
+  *  specific language governing permissions and limitations
+  *  under the License.
+  */
+ package org.apache.causeway.security.simple.authentication;
+ 
+ import java.util.stream.Stream;
+ 
 -import javax.inject.Inject;
 -import javax.inject.Named;
++import jakarta.inject.Inject;
++import jakarta.inject.Named;
+ 
+ import org.springframework.beans.factory.annotation.Qualifier;
+ import org.springframework.security.crypto.password.PasswordEncoder;
+ import org.springframework.stereotype.Service;
+ 
+ import org.apache.causeway.applib.annotation.PriorityPrecedence;
+ import org.apache.causeway.applib.services.iactnlayer.InteractionContext;
+ import org.apache.causeway.applib.services.user.UserMemento;
+ import org.apache.causeway.commons.internal.base._Strings;
+ 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.security.simple.CausewayModuleSecuritySimple;
+ import org.apache.causeway.security.simple.realm.SimpleRealm;
+ 
+ import lombok.NonNull;
+ import lombok.RequiredArgsConstructor;
+ 
+ /**
+  * Simple in-memory {@link Authenticator} implementation.
+  *
+  * @since 2.x {@index}
+  */
+ @Service
+ @Named(CausewayModuleSecuritySimple.NAMESPACE + ".SimpleAuthenticator")
 [email protected](PriorityPrecedence.LATE - 10) // ensure earlier 
than bypass
[email protected](PriorityPrecedence.LATE - 10) // ensure earlier 
than bypass
+ @Qualifier("Simple")
+ @RequiredArgsConstructor(onConstructor_ = {@Inject})
+ public class SimpleAuthenticator implements Authenticator {
+ 
+     protected final SimpleRealm realm;
+     protected final PasswordEncoder passwordEncoder;
+ 
+     @Override
+     public final boolean canAuthenticate(final Class<? extends 
AuthenticationRequest> authenticationRequestClass) {
+         return 
AuthenticationRequestPassword.class.isAssignableFrom(authenticationRequestClass);
+     }
+ 
+     @Override
+     public final InteractionContext authenticate(
+             final AuthenticationRequest request,
+             final String validationCode) {
+ 
+         if(request instanceof AuthenticationRequestPassword) {
+             if (!isValid((AuthenticationRequestPassword) request)) {
+                 return null;
+             }
+         } else {
+             return null; // request type not supported
+         }
+ 
+         var user = UserMemento.ofNameAndRoleNames(request.getName(), 
Stream.concat(
+                     request.streamRoles(),
+                     realm.lookupUserByName(request.getName()).orElseThrow()
+                         .roles()
+                         .stream()
+                         .map(SimpleRealm.Role::name))
+                 )
+                 .withAuthenticationCode(validationCode);
+         return InteractionContext.ofUserWithSystemDefaults(user);
+     }
+ 
+     @Override
+     public final void logout() {
+         // no-op
+     }
+ 
+     protected boolean isValid(final @NonNull AuthenticationRequestPassword 
request) {
+         var plainPass = request.getPassword();
+         return _Strings.isNullOrEmpty(plainPass)
+             ? false
+             : realm.lookupUserByName(request.getName())
+                 .map(SimpleRealm.User::encryptedPass)
+                 
.map(encryptedPass->passwordEncoder.matches(request.getPassword(), 
encryptedPass))
+                 .orElse(false);
+     }
+ 
+ }
+ 
+ 
diff --cc 
security/simple/src/main/java/org/apache/causeway/security/simple/authorization/SimpleAuthorizor.java
index 0000000000,93d432efbb..1e056d1477
mode 000000,100644..100644
--- 
a/security/simple/src/main/java/org/apache/causeway/security/simple/authorization/SimpleAuthorizor.java
+++ 
b/security/simple/src/main/java/org/apache/causeway/security/simple/authorization/SimpleAuthorizor.java
@@@ -1,0 -1,72 +1,72 @@@
+ /*
+  *  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 agreed to in writing,
+  *  software distributed under the License is distributed on an
+  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  *  KIND, either express or implied.  See the License for the
+  *  specific language governing permissions and limitations
+  *  under the License.
+  */
+ package org.apache.causeway.security.simple.authorization;
+ 
+ import java.util.List;
+ 
 -import javax.inject.Inject;
 -import javax.inject.Named;
++import jakarta.inject.Inject;
++import jakarta.inject.Named;
+ 
+ import org.springframework.beans.factory.annotation.Qualifier;
+ import org.springframework.stereotype.Service;
+ 
+ import org.apache.causeway.applib.Identifier;
+ import org.apache.causeway.applib.annotation.PriorityPrecedence;
+ import org.apache.causeway.applib.services.iactnlayer.InteractionContext;
+ import org.apache.causeway.applib.services.user.UserMemento;
+ import org.apache.causeway.core.security.authorization.Authorizor;
+ import org.apache.causeway.security.simple.CausewayModuleSecuritySimple;
+ import org.apache.causeway.security.simple.realm.SimpleRealm;
+ 
+ import lombok.RequiredArgsConstructor;
+ 
+ /**
+  * Simple in-memory {@link Authorizor} implementation.
+  *
+  * @since 2.x {@index}
+  */
+ @Service
+ @Named(CausewayModuleSecuritySimple.NAMESPACE + ".SimpleAuthorizor")
 [email protected](PriorityPrecedence.LATE - 10) // ensure earlier 
than bypass
[email protected](PriorityPrecedence.LATE - 10) // ensure earlier 
than bypass
+ @Qualifier("Simple")
+ @RequiredArgsConstructor(onConstructor_ = {@Inject})
+ public class SimpleAuthorizor implements Authorizor {
+ 
+     protected final SimpleRealm realm;
+ 
+     @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));
+     }
+ 
+     protected List<SimpleRealm.Role> roles(final UserMemento userMemento){
+         var roles = realm.lookupUserByName(userMemento.getName())
+                 .map(SimpleRealm.User::roles)
+                 .orElseGet(List::of);
+         return roles;
+     }
+ 
+ }

Reply via email to