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; + } + + }
