This is an automated email from the ASF dual-hosted git repository.
enapps-enorman pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-extensions-webconsolesecurityprovider.git
The following commit(s) were added to refs/heads/master by this push:
new 14bccdf SLING-13181 migrate to org.apache.felix.webconsole 5.x and
jakarta Servlet (#6)
14bccdf is described below
commit 14bccdfbe82a5b8d9da56e64a972058f3675d4b9
Author: Eric Norman <[email protected]>
AuthorDate: Mon May 4 15:21:25 2026 -0700
SLING-13181 migrate to org.apache.felix.webconsole 5.x and jakarta Servlet
(#6)
---
bnd.bnd | 4 +
pom.xml | 65 +++++-
.../AbstractWebConsoleSecurityProvider.java | 87 --------
.../internal/Activator.java | 5 +-
.../{Activator.java => ConfigConstants.java} | 41 ++--
.../internal/ServicesListener.java | 32 +--
.../internal/SlingWebConsoleSecurityProvider.java | 68 ++++--
.../internal/SlingWebConsoleSecurityProvider2.java | 135 +++++++-----
.../internal/ActivatorTest.java | 63 ++++++
.../internal/ServiceListenerTest.java | 60 ++----
.../SlingWebConsoleSecurityProvider2Test.java | 228 +++++++++++++++++++++
.../SlingWebConsoleSecurityProviderTest.java | 153 ++++++++++++++
12 files changed, 687 insertions(+), 254 deletions(-)
diff --git a/bnd.bnd b/bnd.bnd
index 40a6f22..2a155f5 100644
--- a/bnd.bnd
+++ b/bnd.bnd
@@ -10,3 +10,7 @@ DynamicImport-Package:\
org.apache.sling.api.auth;version="[1.0,2)",\
org.apache.sling.api.resource;version="[2.3,3)",\
org.apache.sling.auth.core;version="[1.0,2)"
+
+# make a copy of private classes that we need
+-includeresource:\
+
@org.apache.felix.webconsole-*.jar!/org/apache/felix/webconsole/internal/servlet/(BasicWebConsoleSecurityProvider*)
diff --git a/pom.xml b/pom.xml
index 6724557..e051149 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,12 @@
</properties>
<dependencies>
+ <!-- JetBrains annotations for null-analysis (SLING-7798) -->
+ <dependency>
+ <groupId>org.jetbrains</groupId>
+ <artifactId>annotations</artifactId>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.framework</artifactId>
@@ -55,22 +61,37 @@
<artifactId>org.osgi.service.cm</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.http.whiteboard</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.util.converter</artifactId>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.webconsole</artifactId>
- <version>4.2.10</version>
+ <version>5.0.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.4.0</version>
+ <version>3.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.auth.core</artifactId>
- <version>1.0.0</version>
+ <version>2.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.servlet</groupId>
+ <artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
@@ -85,8 +106,7 @@
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
- <artifactId>jackrabbit-api</artifactId>
- <version>2.6.0</version>
+ <artifactId>oak-jackrabbit-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
@@ -103,7 +123,21 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.testing.osgi-mock.junit4</artifactId>
- <version>3.3.0</version>
+ <version>3.5.8</version>
+ <scope>test</scope>
+ </dependency>
+ <!-- need a newer jcr-mock version than the indirect one from
sling-mock for SLING-13177 fix.
+ this may be removed if sling-mock updates to this version or
later-->
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.jcr-mock</artifactId>
+ <version>1.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.sling-mock.junit4</artifactId>
+ <version>4.0.6</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -134,4 +168,23 @@
</plugin>
</plugins>
</build>
+ <profiles>
+ <profile>
+ <id>jacoco-report</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <configuration>
+ <!-- exclude the binary classes that were copied
from elsewhere -->
+ <excludes>
+
<exclude>org/apache/felix/webconsole/internal/servlet/*</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
</project>
diff --git
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java
deleted file mode 100644
index 3595c0e..0000000
---
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.sling.extensions.webconsolesecurityprovider.internal;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.felix.webconsole.WebConsoleSecurityProvider;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This is the common base class for the two provider implementations.
- * It handles the configuration of the service.
- */
-public abstract class AbstractWebConsoleSecurityProvider implements
WebConsoleSecurityProvider, ManagedService {
-
- // name of the property providing list of authorized users
- private static final String PROP_USERS = "users";
-
- // default user being authorized
- public static final String PROP_GROUPS_DEFAULT_USER = "admin";
-
- // name of the property providing list of groups whose members are
- // authorized
- private static final String PROP_GROUPS = "groups";
-
- /** default logger */
- protected final Logger logger = LoggerFactory.getLogger(getClass());
-
- protected Set<String> users =
Collections.singleton(PROP_GROUPS_DEFAULT_USER);
-
- protected Set<String> groups = Collections.emptySet();
-
- /**
- * Handle configuration
- * @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary)
- */
- @Override
- public void updated(final Dictionary<String, ?> properties) throws
ConfigurationException {
- this.users = toSet(properties == null ? null :
properties.get(PROP_USERS), PROP_GROUPS_DEFAULT_USER);
- this.groups = toSet(properties == null ? null :
properties.get(PROP_GROUPS), null);
- }
-
- private Set<String> toSet(final Object configObj, final String
defaultUser) {
- final Set<String> groups = new HashSet<String>();
- if (configObj instanceof String) {
- groups.add((String) configObj);
- } else if (configObj instanceof Collection<?>) {
- for (Object obj : ((Collection<?>) configObj)) {
- if (obj instanceof String) {
- groups.add((String) obj);
- }
- }
- } else if (configObj instanceof String[]) {
- for (String string : ((String[]) configObj)) {
- if (string != null) {
- groups.add(string);
- }
- }
- } else if (configObj == null && defaultUser != null) {
- groups.add(defaultUser);
- }
- return groups;
- }
-}
diff --git
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java
index 127203c..59e37ca 100644
---
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java
+++
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java
@@ -18,6 +18,7 @@
*/
package org.apache.sling.extensions.webconsolesecurityprovider.internal;
+import org.jetbrains.annotations.NotNull;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
@@ -29,7 +30,7 @@ public class Activator implements BundleActivator {
* @see
org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
@Override
- public void start(final BundleContext context) throws Exception {
+ public void start(@NotNull final BundleContext context) throws Exception {
listener = new ServicesListener(context);
}
@@ -37,7 +38,7 @@ public class Activator implements BundleActivator {
* @see
org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
@Override
- public void stop(final BundleContext context) throws Exception {
+ public void stop(@NotNull final BundleContext context) throws Exception {
if (listener != null) {
listener.deactivate();
listener = null;
diff --git
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ConfigConstants.java
similarity index 55%
copy from
src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java
copy to
src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ConfigConstants.java
index 127203c..ab5286f 100644
---
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java
+++
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ConfigConstants.java
@@ -18,29 +18,28 @@
*/
package org.apache.sling.extensions.webconsolesecurityprovider.internal;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
+import java.util.Collections;
+import java.util.Set;
-public class Activator implements BundleActivator {
-
- private ServicesListener listener;
+/**
+ * This is the common constants for the two provider implementations.
+ */
+class ConfigConstants {
- /**
- * @see
org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
- */
- @Override
- public void start(final BundleContext context) throws Exception {
- listener = new ServicesListener(context);
+ private ConfigConstants() {
+ /* This utility class should not be instantiated */
}
- /**
- * @see
org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
- */
- @Override
- public void stop(final BundleContext context) throws Exception {
- if (listener != null) {
- listener.deactivate();
- listener = null;
- }
- }
+ // name of the property providing list of authorized users
+ static final String PROP_USERS = "users";
+
+ // default user being authorized
+ static final Set<String> PROP_DEFAULT_USERS = Set.of("admin");
+
+ // name of the property providing list of groups whose members are
+ // authorized
+ static final String PROP_GROUPS = "groups";
+
+ // default user being authorized
+ static final Set<String> PROP_DEFAULT_GROUPS = Collections.emptySet();
}
diff --git
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java
index 708f8da..5478849 100644
---
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java
+++
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java
@@ -17,29 +17,11 @@
* under the License.
*/
package org.apache.sling.extensions.webconsolesecurityprovider.internal;
-/*
- * 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.
- */
import java.util.Dictionary;
import java.util.Hashtable;
-import org.apache.felix.webconsole.WebConsoleSecurityProvider;
+import org.apache.felix.webconsole.spi.SecurityProvider;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
@@ -60,7 +42,7 @@ import org.slf4j.LoggerFactory;
* <li> "jcrAuth": always authenticate against the JCR repository even if
Sling Authentication is possible.</li>
* <li> "slingAuth": always use SlingAuthentication
* <li> no value (default) : Use SlingAuthentication if available, fallback
to JCR repository
- * <li> If an invalid value is specifed, the value is ignored and the
default is used
+ * <li> If an invalid value is specified, the value is ignored and the
default is used
* </ul>
*/
public class ServicesListener {
@@ -202,26 +184,26 @@ public class ServicesListener {
}
private void registerProviderSling(final Object authSupport, final Object
authenticator) {
- final Dictionary<String, Object> props = new Hashtable<String,
Object>();
+ final Dictionary<String, Object> props = new Hashtable<>();
props.put(Constants.SERVICE_PID,
SlingWebConsoleSecurityProvider.class.getName());
props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Web Console
Security Provider 2");
props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
props.put("webconsole.security.provider.id",
"org.apache.sling.extensions.webconsolesecurityprovider2");
this.provider2Reg = this.bundleContext.registerService(
- new String[] {ManagedService.class.getName(),
WebConsoleSecurityProvider.class.getName()},
+ new String[] {ManagedService.class.getName(),
SecurityProvider.class.getName()},
new SlingWebConsoleSecurityProvider2(authSupport,
authenticator),
props);
}
private void registerProviderJcr(final Object repository) {
- final Dictionary<String, Object> props = new Hashtable<String,
Object>();
+ final Dictionary<String, Object> props = new Hashtable<>();
props.put(Constants.SERVICE_PID,
SlingWebConsoleSecurityProvider.class.getName());
props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Web Console
Security Provider");
props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
props.put("webconsole.security.provider.id",
"org.apache.sling.extensions.webconsolesecurityprovider");
this.providerReg = this.bundleContext.registerService(
- new String[] {ManagedService.class.getName(),
WebConsoleSecurityProvider.class.getName()},
- new SlingWebConsoleSecurityProvider(repository),
+ new String[] {ManagedService.class.getName(),
SecurityProvider.class.getName()},
+ new SlingWebConsoleSecurityProvider(this.bundleContext,
repository),
props);
}
diff --git
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider.java
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider.java
index 1b91b38..db8d0a8 100644
---
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider.java
+++
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider.java
@@ -24,13 +24,30 @@ import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
+import java.util.Dictionary;
import java.util.Iterator;
+import java.util.Set;
+import
org.apache.felix.webconsole.internal.servlet.BasicWebConsoleSecurityProvider;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.util.converter.Converter;
+import org.osgi.util.converter.Converters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static
org.apache.sling.extensions.webconsolesecurityprovider.internal.ConfigConstants.PROP_DEFAULT_GROUPS;
+import static
org.apache.sling.extensions.webconsolesecurityprovider.internal.ConfigConstants.PROP_DEFAULT_USERS;
+import static
org.apache.sling.extensions.webconsolesecurityprovider.internal.ConfigConstants.PROP_GROUPS;
+import static
org.apache.sling.extensions.webconsolesecurityprovider.internal.ConfigConstants.PROP_USERS;
/**
* The <code>SlingWebConsoleSecurityProvider</code> is security provider for
the
@@ -44,15 +61,39 @@ import org.apache.jackrabbit.api.security.user.UserManager;
* only registered as a security provider service once such a JCR Repository is
* available.
*/
-public class SlingWebConsoleSecurityProvider extends
AbstractWebConsoleSecurityProvider {
+public class SlingWebConsoleSecurityProvider extends
BasicWebConsoleSecurityProvider implements ManagedService {
+
+ /** default logger */
+ protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+ protected Set<String> users = PROP_DEFAULT_USERS;
+ protected Set<String> groups = PROP_DEFAULT_GROUPS;
private Repository repository;
- public SlingWebConsoleSecurityProvider(final Object repository) {
+ public SlingWebConsoleSecurityProvider(
+ @NotNull final BundleContext bundleContext, @NotNull final Object
repository) {
+ super(bundleContext);
this.repository = (Repository) repository;
}
- // ---------- SCR integration
+ /**
+ * Handle configuration
+ * @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void updated(@Nullable Dictionary<String, ?> properties) throws
ConfigurationException {
+ final Converter converter = Converters.standardConverter();
+ this.users = converter
+ .convert(properties == null ? null :
properties.get(PROP_USERS))
+ .defaultValue(PROP_DEFAULT_USERS)
+ .to(Set.class);
+ this.groups = converter
+ .convert(properties == null ? null :
properties.get(PROP_GROUPS))
+ .defaultValue(PROP_DEFAULT_GROUPS)
+ .to(Set.class);
+ }
/**
* Authenticates and authorizes the user identified by the user name and
@@ -77,26 +118,25 @@ public class SlingWebConsoleSecurityProvider extends
AbstractWebConsoleSecurityP
* @param password The password to authenticate the user. This may be
* <code>null</code> to assume an empty password.
* @return The <code>userName</code> is currently returned to indicate
- * successfull authentication.
+ * successful authentication.
* @throws NullPointerException if <code>userName</code> is
* <code>null</code>.
*/
@Override
- public Object authenticate(String userName, String password) {
+ public @Nullable Object authenticate(@NotNull String userName, @Nullable
String password) {
final Credentials creds =
new SimpleCredentials(userName, (password == null) ? new
char[0] : password.toCharArray());
Session session = null;
try {
session = repository.login(creds);
- if (session instanceof JackrabbitSession) {
- UserManager umgr = ((JackrabbitSession)
session).getUserManager();
+ if (session instanceof JackrabbitSession jrSession) {
+ UserManager umgr = jrSession.getUserManager();
String userId = session.getUserID();
Authorizable a = umgr.getAuthorizable(userId);
if (a instanceof User) {
-
// check users
if (users.contains(userId)) {
- return true;
+ return userName;
}
// check groups
@@ -135,14 +175,4 @@ public class SlingWebConsoleSecurityProvider extends
AbstractWebConsoleSecurityP
// no success (see log)
return null;
}
-
- /**
- * All users authenticated with the repository and being a member of the
- * authorized groups are granted access for all roles in the Web Console.
- */
- @Override
- public boolean authorize(Object user, String role) {
- logger.debug("authorize: Grant user {} access for role {}", user,
role);
- return true;
- }
}
diff --git
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java
index 30be211..bf8aaea 100644
---
a/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java
+++
b/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java
@@ -20,12 +20,14 @@ package
org.apache.sling.extensions.webconsolesecurityprovider.internal;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import java.util.Dictionary;
import java.util.Iterator;
+import java.util.Set;
-import org.apache.felix.webconsole.WebConsoleSecurityProvider3;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.felix.webconsole.spi.SecurityProvider;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
@@ -34,6 +36,19 @@ import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.api.auth.Authenticator;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.auth.core.AuthenticationSupport;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.util.converter.Converter;
+import org.osgi.util.converter.Converters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static
org.apache.sling.extensions.webconsolesecurityprovider.internal.ConfigConstants.PROP_DEFAULT_GROUPS;
+import static
org.apache.sling.extensions.webconsolesecurityprovider.internal.ConfigConstants.PROP_DEFAULT_USERS;
+import static
org.apache.sling.extensions.webconsolesecurityprovider.internal.ConfigConstants.PROP_GROUPS;
+import static
org.apache.sling.extensions.webconsolesecurityprovider.internal.ConfigConstants.PROP_USERS;
/**
* The <code>SlingWebConsoleSecurityProvider</code> is security provider for
the
@@ -47,77 +62,102 @@ import org.apache.sling.auth.core.AuthenticationSupport;
* only registered as a security provider service once such a JCR Repository is
* available.
*/
-public class SlingWebConsoleSecurityProvider2 extends
AbstractWebConsoleSecurityProvider
- implements WebConsoleSecurityProvider3 {
+public class SlingWebConsoleSecurityProvider2 implements SecurityProvider,
ManagedService {
+
+ /** default logger */
+ protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+ protected Set<String> users = PROP_DEFAULT_USERS;
+ protected Set<String> groups = PROP_DEFAULT_GROUPS;
private final AuthenticationSupport authentiationSupport;
private final Authenticator authenticator;
- public SlingWebConsoleSecurityProvider2(final Object support, final Object
authenticator) {
+ public SlingWebConsoleSecurityProvider2(@NotNull final Object support,
@NotNull final Object authenticator) {
this.authentiationSupport = (AuthenticationSupport) support;
this.authenticator = (Authenticator) authenticator;
}
/**
- * @see
org.apache.felix.webconsole.WebConsoleSecurityProvider2#authenticate(javax.servlet.http.HttpServletRequest,
javax.servlet.http.HttpServletResponse)
+ * Handle configuration
+ * @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary)
*/
+ @SuppressWarnings("unchecked")
@Override
- public boolean authenticate(final HttpServletRequest request, final
HttpServletResponse response) {
- if (this.authentiationSupport.handleSecurity(request, response)) {
- // get ResourceResolver (set by AuthenticationSupport)
- Object resolverObject =
request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER);
- final ResourceResolver resolver =
- (resolverObject instanceof ResourceResolver) ?
(ResourceResolver) resolverObject : null;
- if (resolver != null) {
- final Session session = resolver.adaptTo(Session.class);
- if (session != null) {
- try {
- final User u = this.authenticate(session);
- if (u != null) {
- request.setAttribute(USER_ATTRIBUTE, u);
- return true;
- }
- } catch (final Exception re) {
- logger.info(
- "authenticate: Generic problem trying grant
User " + " access to the Web Console", re);
- }
- }
- }
- if (request.getAuthType() == null) {
- this.authenticator.login(request, response);
- }
- }
- return false;
+ public void updated(@Nullable Dictionary<String, ?> properties) throws
ConfigurationException {
+ final Converter converter = Converters.standardConverter();
+ this.users = converter
+ .convert(properties == null ? null :
properties.get(PROP_USERS))
+ .defaultValue(PROP_DEFAULT_USERS)
+ .to(Set.class);
+ this.groups = converter
+ .convert(properties == null ? null :
properties.get(PROP_GROUPS))
+ .defaultValue(PROP_DEFAULT_GROUPS)
+ .to(Set.class);
}
+ /**
+ * All users authenticated with the repository and being a member of the
+ * authorized groups are granted access for all roles in the Web Console.
+ */
@Override
- public void logout(HttpServletRequest request, HttpServletResponse
response) {
- this.authenticator.logout(request, response);
+ public boolean authorize(@NotNull Object user, @NotNull String role) {
+ logger.debug("authorize: Grant user {} access for role {}", user,
role);
+ return true;
}
+ /**
+ * @see
org.apache.felix.webconsole.spi.SecurityProvider#authenticate(jakarta.servlet.http.HttpServletRequest,
jakarta.servlet.http.HttpServletResponse)
+ */
@Override
- public User authenticate(String userName, String password) {
- return null; // this method is never invoked
+ public @Nullable Object authenticate(
+ @NotNull final HttpServletRequest request, @NotNull final
HttpServletResponse response) {
+ try {
+ if (this.authentiationSupport.handleSecurity(request, response)) {
+ // get ResourceResolver (set by AuthenticationSupport)
+ Object resolverObject =
request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER);
+ if (resolverObject instanceof ResourceResolver resolver) {
+ final Session session = resolver.adaptTo(Session.class);
+ if (session != null) {
+ try {
+ final User u = this.authenticate(session);
+ if (u != null) {
+ return u.getID();
+ }
+ } catch (final Exception re) {
+ logger.info(
+ "authenticate: Generic problem trying
grant User access to the Web Console", re);
+ }
+ }
+ }
+ if (request.getAuthType() == null) {
+ this.authenticator.login(request, response);
+ }
+ }
+ } finally {
+ this.authentiationSupport.finishSecurity(request, response);
+ }
+ return null;
}
- private User authenticate(final Session session) throws
RepositoryException {
+ protected @Nullable User authenticate(@NotNull final Session session)
throws RepositoryException {
String userId = session.getUserID();
- if (session instanceof JackrabbitSession) {
- UserManager umgr = ((JackrabbitSession) session).getUserManager();
+ if (session instanceof JackrabbitSession jrSession) {
+ UserManager umgr = jrSession.getUserManager();
Authorizable a = umgr.getAuthorizable(userId);
- if (a instanceof User) {
+ if (a instanceof User u) {
// check users
if (users.contains(userId)) {
- return (User) a;
+ return u;
}
// check groups
Iterator<Group> gi = a.memberOf();
while (gi.hasNext()) {
if (groups.contains(gi.next().getID())) {
- return (User) a;
+ return u;
}
}
@@ -134,13 +174,8 @@ public class SlingWebConsoleSecurityProvider2 extends
AbstractWebConsoleSecurity
return null;
}
- /**
- * All users authenticated with the repository and being a member of the
- * authorized groups are granted access for all roles in the Web Console.
- */
@Override
- public boolean authorize(Object user, String role) {
- logger.debug("authorize: Grant user {} access for role {}", user,
role);
- return true;
+ public void logout(@NotNull HttpServletRequest request, @NotNull
HttpServletResponse response) {
+ this.authenticator.logout(request, response);
}
}
diff --git
a/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ActivatorTest.java
b/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ActivatorTest.java
new file mode 100644
index 0000000..7019bc5
--- /dev/null
+++
b/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ActivatorTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.sling.extensions.webconsolesecurityprovider.internal;
+
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.Test.None;
+import org.osgi.framework.BundleContext;
+
+/**
+ *
+ */
+public class ActivatorTest {
+
+ @Rule
+ public OsgiContext context = new OsgiContext();
+
+ private Activator activator = new Activator();
+
+ /**
+ * Test method for {@link
org.apache.sling.extensions.webconsolesecurityprovider.internal.Activator#start(org.osgi.framework.BundleContext)}.
+ */
+ @Test(expected = None.class)
+ public void testStart() throws Exception {
+ final @NotNull BundleContext bundleContext = context.bundleContext();
+ activator.start(bundleContext);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.extensions.webconsolesecurityprovider.internal.Activator#stop(org.osgi.framework.BundleContext)}.
+ */
+ @Test(expected = None.class)
+ public void testStop() throws Exception {
+ final @NotNull BundleContext bundleContext = context.bundleContext();
+
+ // start
+ activator.start(bundleContext);
+
+ // stop
+ activator.stop(bundleContext);
+
+ // stop one more time for code coverage
+ activator.stop(bundleContext);
+ }
+}
diff --git
a/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServiceListenerTest.java
b/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServiceListenerTest.java
index 322d154..e2df3b2 100644
---
a/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServiceListenerTest.java
+++
b/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServiceListenerTest.java
@@ -17,28 +17,10 @@
* under the License.
*/
package org.apache.sling.extensions.webconsolesecurityprovider.internal;
-/*
- * 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.
- */
import javax.jcr.Repository;
-import org.apache.felix.webconsole.WebConsoleSecurityProvider;
+import org.apache.felix.webconsole.spi.SecurityProvider;
import org.apache.sling.api.auth.Authenticator;
import org.apache.sling.auth.core.AuthenticationSupport;
import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
@@ -47,9 +29,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.osgi.framework.BundleContext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -78,12 +58,14 @@ public class ServiceListenerTest {
@After
public void shutdown() {
- listener.deactivate();
+ if (listener != null) {
+ listener.deactivate();
+ }
}
@Test
public void testDefaultAuth() {
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertNoSecurityProviderRegistered();
context.registerService(Repository.class, repository);
@@ -103,7 +85,7 @@ public class ServiceListenerTest {
public void testWithSlingAuth() {
try {
System.setProperty(ServicesListener.WEBCONSOLE_AUTH_TYPE,
ServicesListener.SLING_AUTH);
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertNoSecurityProviderRegistered();
context.registerService(Repository.class, repository);
@@ -126,7 +108,7 @@ public class ServiceListenerTest {
public void testWithForcedJcrAuth() {
try {
System.setProperty(ServicesListener.WEBCONSOLE_AUTH_TYPE,
ServicesListener.JCR_AUTH);
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertNoSecurityProviderRegistered();
// no matter what is registered, always the auth against the repo
needs to be there
@@ -150,19 +132,19 @@ public class ServiceListenerTest {
@Test
public void testGetAuthType() {
try {
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertEquals(ServicesListener.AuthType.DEFAULT,
listener.getAuthType());
System.setProperty(ServicesListener.WEBCONSOLE_AUTH_TYPE,
ServicesListener.JCR_AUTH);
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertEquals(ServicesListener.AuthType.JCR,
listener.getAuthType());
System.setProperty(ServicesListener.WEBCONSOLE_AUTH_TYPE,
ServicesListener.SLING_AUTH);
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertEquals(ServicesListener.AuthType.SLING,
listener.getAuthType());
System.setProperty(ServicesListener.WEBCONSOLE_AUTH_TYPE,
"invalid");
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertEquals(ServicesListener.AuthType.DEFAULT,
listener.getAuthType());
} finally {
System.getProperties().remove(ServicesListener.WEBCONSOLE_AUTH_TYPE);
@@ -172,21 +154,21 @@ public class ServiceListenerTest {
@Test
public void testGetTargetState() {
try {
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertEquals(ServicesListener.State.NONE,
listener.getTargetState(false, false));
assertEquals(ServicesListener.State.PROVIDER_JCR,
listener.getTargetState(false, true));
assertEquals(ServicesListener.State.PROVIDER_SLING,
listener.getTargetState(true, false));
assertEquals(ServicesListener.State.PROVIDER_SLING,
listener.getTargetState(true, true));
System.setProperty(ServicesListener.WEBCONSOLE_AUTH_TYPE,
ServicesListener.JCR_AUTH);
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertEquals(ServicesListener.State.NONE,
listener.getTargetState(false, false));
assertEquals(ServicesListener.State.PROVIDER_JCR,
listener.getTargetState(false, true));
assertEquals(ServicesListener.State.NONE,
listener.getTargetState(true, false));
assertEquals(ServicesListener.State.PROVIDER_JCR,
listener.getTargetState(true, true));
System.setProperty(ServicesListener.WEBCONSOLE_AUTH_TYPE,
ServicesListener.SLING_AUTH);
- listener = new
ServicesListener(wrapForValidProperties(context.bundleContext()));
+ listener = new ServicesListener(context.bundleContext());
assertEquals(ServicesListener.State.NONE,
listener.getTargetState(false, false));
assertEquals(ServicesListener.State.NONE,
listener.getTargetState(false, true));
assertEquals(ServicesListener.State.PROVIDER_SLING,
listener.getTargetState(true, false));
@@ -196,16 +178,6 @@ public class ServiceListenerTest {
}
}
- // until https://issues.apache.org/jira/browse/SLING-11505 is implemented
- private BundleContext wrapForValidProperties(BundleContext bc) {
- BundleContext spy = Mockito.spy(bc);
-
Mockito.when(spy.getProperty(Mockito.anyString())).thenAnswer(invocation -> {
- String key = (String) invocation.getArguments()[0];
- return System.getProperty(key);
- });
- return spy;
- }
-
// Helpers
private void assertRepositoryRegistered() {
@@ -224,7 +196,7 @@ public class ServiceListenerTest {
assertNull(getSecurityProvider());
}
- private WebConsoleSecurityProvider getSecurityProvider() {
- return context.getService(WebConsoleSecurityProvider.class);
+ private SecurityProvider getSecurityProvider() {
+ return context.getService(SecurityProvider.class);
}
}
diff --git
a/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2Test.java
b/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2Test.java
new file mode 100644
index 0000000..6254cc0
--- /dev/null
+++
b/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2Test.java
@@ -0,0 +1,228 @@
+/*
+ * 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.sling.extensions.webconsolesecurityprovider.internal;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.sling.api.auth.Authenticator;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.auth.core.AuthenticationSupport;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import
org.apache.sling.testing.mock.sling.servlet.MockSlingJakartaHttpServletRequest;
+import
org.apache.sling.testing.mock.sling.servlet.MockSlingJakartaHttpServletResponse;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.service.cm.ConfigurationException;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.withSettings;
+
+/**
+ *
+ */
+public class SlingWebConsoleSecurityProvider2Test {
+
+ @Rule
+ public SlingContext context = new
SlingContext(ResourceResolverType.JCR_MOCK);
+
+ private SlingWebConsoleSecurityProvider2 provider;
+
+ private AuthenticationSupport support;
+ private Authenticator authenticator;
+
+ @Before
+ public void before() {
+ support = Mockito.mock(AuthenticationSupport.class);
+ authenticator = Mockito.mock(Authenticator.class);
+ provider = new SlingWebConsoleSecurityProvider2(support,
authenticator);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.extensions.webconsolesecurityprovider.internal.SlingWebConsoleSecurityProvider2#updated(java.util.Dictionary)}.
+ */
+ @Test
+ public void testUpdated() throws ConfigurationException {
+ provider.updated(null);
+ assertEquals(ConfigConstants.PROP_DEFAULT_USERS, provider.users);
+ assertEquals(ConfigConstants.PROP_DEFAULT_GROUPS, provider.groups);
+
+ provider.updated(new Hashtable<>(Map.of()));
+ assertEquals(ConfigConstants.PROP_DEFAULT_USERS, provider.users);
+ assertEquals(ConfigConstants.PROP_DEFAULT_GROUPS, provider.groups);
+
+ provider.updated(new Hashtable<>(Map.of("users", "user1", "groups",
"group1")));
+ assertEquals(Set.of("user1"), provider.users);
+ assertEquals(Set.of("group1"), provider.groups);
+
+ provider.updated(new Hashtable<>(
+ Map.of("users", new String[] {"user1", "user2"}, "groups", new
String[] {"group1", "group2"})));
+ assertEquals(Set.of("user1", "user2"), provider.users);
+ assertEquals(Set.of("group1", "group2"), provider.groups);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.extensions.webconsolesecurityprovider.internal.SlingWebConsoleSecurityProvider2#authenticate(jakarta.servlet.http.HttpServletRequest,
jakarta.servlet.http.HttpServletResponse)}.
+ */
+ @Test
+ public void testAuthenticate() throws RepositoryException,
ConfigurationException {
+ final @NotNull MockSlingJakartaHttpServletRequest request =
context.jakartaRequest();
+ final @NotNull MockSlingJakartaHttpServletResponse response =
context.jakartaResponse();
+
+ // security not handled
+ Mockito.doReturn(false)
+ .when(support)
+ .handleSecurity(any(HttpServletRequest.class),
any(HttpServletResponse.class));
+ assertNull(provider.authenticate(request, response));
+
+ // security handled without ResourceResolver (set by
AuthenticationSupport)
+ Mockito.doReturn(true)
+ .when(support)
+ .handleSecurity(any(HttpServletRequest.class),
any(HttpServletResponse.class));
+ assertNull(provider.authenticate(request, response));
+
+ // security handled with ResourceResolver (set by
AuthenticationSupport)
+ final @NotNull ResourceResolver rr = context.resourceResolver();
+ request.setAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER,
rr);
+ // for code coverage simulate no auth challenge path
+ request.setAuthType("FORMS");
+ assertNull(provider.authenticate(request, response));
+
+ // for code coverage simulate auth challenge path
+ request.setAuthType(null);
+ assertNull(provider.authenticate(request, response));
+
+ // create a user
+ UserManager userManager = ((JackrabbitSession)
rr.adaptTo(Session.class)).getUserManager();
+ final @NotNull User user1 = userManager.createUser("admin", "test1");
+
+ // user does exist, and in the configuration
+ assertEquals("admin", provider.authenticate(request, response));
+
+ // change the users in the configuration
+ provider.updated(new Hashtable<>(Map.of("users", "test1")));
+
+ // user does exist, but not in the configuration
+ assertNull(provider.authenticate(request, response));
+
+ // add user to a group
+ final @NotNull Group group1 = userManager.createGroup("group1");
+ group1.addMember(user1);
+ final @NotNull Group group2 = userManager.createGroup("group2");
+
+ // change the users in the configuration
+ provider.updated(new Hashtable<>(Map.of("users", "test1", "groups",
"group2")));
+
+ // user does exist, but not in the groups configuration
+ assertNull(provider.authenticate(request, response));
+
+ // add to the configured group
+ group2.addMember(user1);
+ // user does exist, and in the groups configuration
+ assertEquals("admin", provider.authenticate(request, response));
+ }
+
+ @Test
+ public void testAuthenticateWithNoSession() {
+ final @NotNull MockSlingJakartaHttpServletRequest request =
context.jakartaRequest();
+ final @NotNull MockSlingJakartaHttpServletResponse response =
context.jakartaResponse();
+
+ // security handled
+ Mockito.doReturn(true)
+ .when(support)
+ .handleSecurity(any(HttpServletRequest.class),
any(HttpServletResponse.class));
+
+ // security handled with ResourceResolver (set by
AuthenticationSupport)
+ final @NotNull ResourceResolver rr =
Mockito.spy(context.resourceResolver());
+ request.setAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER,
rr);
+
+ // simulate an null session
+ Mockito.doReturn(null).when(rr).adaptTo(Session.class);
+
+ // expected no user resolved and null returned
+ assertNull(provider.authenticate(request, response));
+ }
+
+ @Test
+ public void testAuthenticateWithCaughtException() throws
RepositoryException {
+ final @NotNull MockSlingJakartaHttpServletRequest request =
context.jakartaRequest();
+ final @NotNull MockSlingJakartaHttpServletResponse response =
context.jakartaResponse();
+
+ // security handled
+ Mockito.doReturn(true)
+ .when(support)
+ .handleSecurity(any(HttpServletRequest.class),
any(HttpServletResponse.class));
+
+ // security handled with ResourceResolver (set by
AuthenticationSupport)
+ final @NotNull ResourceResolver rr =
Mockito.spy(context.resourceResolver());
+ request.setAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER,
rr);
+
+ // simulate an exception thrown
+ final Session mockSession =
+ Mockito.mock(Session.class,
withSettings().extraInterfaces(JackrabbitSession.class));
+ Mockito.doThrow(UnsupportedRepositoryOperationException.class)
+ .when((JackrabbitSession) mockSession)
+ .getUserManager();
+ Mockito.doReturn(mockSession).when(rr).adaptTo(Session.class);
+
+ // expected exception caught, message logged and null returned
+ assertNull(provider.authenticate(request, response));
+ }
+
+ @Test
+ public void testAuthenticateWithoutJackrabbitSession() throws
RepositoryException {
+ final Session mockSession = Mockito.mock(Session.class);
+ Mockito.doReturn("test1").when(mockSession).getUserID();
+ assertNull(provider.authenticate(mockSession));
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.extensions.webconsolesecurityprovider.internal.SlingWebConsoleSecurityProvider2#logout(jakarta.servlet.http.HttpServletRequest,
jakarta.servlet.http.HttpServletResponse)}.
+ */
+ @Test(expected = org.junit.Test.None.class)
+ public void testLogout() {
+ final @NotNull MockSlingJakartaHttpServletRequest request =
context.jakartaRequest();
+ final @NotNull MockSlingJakartaHttpServletResponse response =
context.jakartaResponse();
+ provider.logout(request, response);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.extensions.webconsolesecurityprovider.internal.SlingWebConsoleSecurityProvider2#authorize(java.lang.Object,
java.lang.String)}.
+ */
+ @Test
+ public void testAuthorize() {
+ assertTrue(provider.authorize("testuser1", "role1"));
+ }
+}
diff --git
a/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProviderTest.java
b/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProviderTest.java
new file mode 100644
index 0000000..e4db003
--- /dev/null
+++
b/src/test/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProviderTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.sling.extensions.webconsolesecurityprovider.internal;
+
+import javax.jcr.Credentials;
+import javax.jcr.LoginException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.service.cm.ConfigurationException;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+
+/**
+ *
+ */
+public class SlingWebConsoleSecurityProviderTest {
+
+ @Rule
+ public SlingContext context = new
SlingContext(ResourceResolverType.JCR_MOCK);
+
+ private Repository mockRepo;
+ private SlingWebConsoleSecurityProvider provider;
+
+ @Before
+ public void before() {
+ mockRepo =
Mockito.spy(context.resourceResolver().adaptTo(Session.class).getRepository());
+ provider = new
SlingWebConsoleSecurityProvider(context.bundleContext(), mockRepo);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.extensions.webconsolesecurityprovider.internal.SlingWebConsoleSecurityProvider#updated(java.util.Dictionary)}.
+ */
+ @Test
+ public void testUpdated() throws ConfigurationException {
+ provider.updated(null);
+ assertEquals(ConfigConstants.PROP_DEFAULT_USERS, provider.users);
+ assertEquals(ConfigConstants.PROP_DEFAULT_GROUPS, provider.groups);
+
+ provider.updated(new Hashtable<>(Map.of()));
+ assertEquals(ConfigConstants.PROP_DEFAULT_USERS, provider.users);
+ assertEquals(ConfigConstants.PROP_DEFAULT_GROUPS, provider.groups);
+
+ provider.updated(new Hashtable<>(Map.of("users", "user1", "groups",
"group1")));
+ assertEquals(Set.of("user1"), provider.users);
+ assertEquals(Set.of("group1"), provider.groups);
+
+ provider.updated(new Hashtable<>(
+ Map.of("users", new String[] {"user1", "user2"}, "groups", new
String[] {"group1", "group2"})));
+ assertEquals(Set.of("user1", "user2"), provider.users);
+ assertEquals(Set.of("group1", "group2"), provider.groups);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.extensions.webconsolesecurityprovider.internal.SlingWebConsoleSecurityProvider#authenticate(java.lang.String,
java.lang.String)}.
+ */
+ @Test
+ public void testAuthenticate() throws RepositoryException,
ConfigurationException {
+ // user does not exist
+ assertNull(provider.authenticate("test1", "test1"));
+
+ // null password for code coverage
+ assertNull(provider.authenticate("test1", null));
+
+ // create a user
+ UserManager userManager = ((JackrabbitSession)
mockRepo.login()).getUserManager();
+ userManager.createUser("test1", "test1");
+
+ // user does exist, but not in the configuration
+ assertNull(provider.authenticate("test1", "test1"));
+
+ // add the user to the configuration
+ provider.updated(new Hashtable<>(Map.of("users", "test1")));
+
+ // user does exist, and also in the configuration
+ assertEquals("test1", provider.authenticate("test1", "test1"));
+
+ // a second user who is in a group
+ final @NotNull User user2 = userManager.createUser("test2", "test2");
+ final @NotNull Group group1 = userManager.createGroup("group1");
+ group1.addMember(user2);
+
+ // user does exist and a not a member of a configured group
+ assertNull(provider.authenticate("test2", "test2"));
+
+ // add the group to the configuration
+ provider.updated(new Hashtable<>(Map.of("groups", "group1")));
+
+ // user does exist and a member of a configured group
+ assertEquals("test2", provider.authenticate("test2", "test2"));
+ }
+
+ @Test
+ public void testAuthenticateWithoutJackrabbitSession() throws
RepositoryException {
+ // simulate the login return some non-jackrabbit session impl
+ final Session mockSession = Mockito.mock(Session.class);
+
Mockito.doReturn(mockSession).when(mockRepo).login(any(Credentials.class));
+
+ // user does not exist
+ assertNull(provider.authenticate("test1", "test1"));
+ }
+
+ @Test
+ public void testAuthenticateWithLoginException() throws
RepositoryException {
+ // simulate the login throwing an exception
+
Mockito.doThrow(LoginException.class).when(mockRepo).login(any(Credentials.class));
+
+ // user does not exist
+ assertNull(provider.authenticate("test1", "test1"));
+ }
+
+ @Test
+ public void testAuthenticateWithOtherException() throws
RepositoryException {
+ // simulate the login throwing an exception
+
Mockito.doThrow(RuntimeException.class).when(mockRepo).login(any(Credentials.class));
+
+ // user does not exist
+ assertNull(provider.authenticate("test1", "test1"));
+ }
+}