Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A58AD10768 for ; Mon, 21 Oct 2013 08:12:45 +0000 (UTC) Received: (qmail 81045 invoked by uid 500); 21 Oct 2013 08:12:44 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 80921 invoked by uid 500); 21 Oct 2013 08:12:39 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 80895 invoked by uid 99); 21 Oct 2013 08:12:36 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 21 Oct 2013 08:12:36 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 21 Oct 2013 08:12:28 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 5CED923888E4; Mon, 21 Oct 2013 08:12:08 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1534058 - in /sling/trunk/bundles/extensions/webconsolesecurityprovider: ./ src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ src/main/resources/ Date: Mon, 21 Oct 2013 08:12:08 -0000 To: commits@sling.apache.org From: cziegeler@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20131021081208.5CED923888E4@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: cziegeler Date: Mon Oct 21 08:12:07 2013 New Revision: 1534058 URL: http://svn.apache.org/r1534058 Log: SLING-3193 : Implement WebConsoleSecurityProvider2 for integration with Sling Authenticator Added: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java (with props) sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java (with props) sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java (with props) sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java (with props) Removed: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/resources/ Modified: sling/trunk/bundles/extensions/webconsolesecurityprovider/pom.xml sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider.java Modified: sling/trunk/bundles/extensions/webconsolesecurityprovider/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/webconsolesecurityprovider/pom.xml?rev=1534058&r1=1534057&r2=1534058&view=diff ============================================================================== --- sling/trunk/bundles/extensions/webconsolesecurityprovider/pom.xml (original) +++ sling/trunk/bundles/extensions/webconsolesecurityprovider/pom.xml Mon Oct 21 08:12:07 2013 @@ -56,6 +56,13 @@ org.apache.felix maven-bundle-plugin true + + + + org.apache.sling.extensions.webconsolesecurityprovider.internal.Activator + + + @@ -74,19 +81,43 @@ + org.osgi + org.osgi.core + + + org.osgi + org.osgi.compendium + + org.apache.felix org.apache.felix.webconsole - 3.1.0 + 4.2.0 + provided + + + org.apache.sling + org.apache.sling.api + 2.4.0 provided + org.apache.sling + org.apache.sling.auth.core + 1.0.0 + provided + + + javax.servlet + servlet-api + + javax.jcr jcr org.apache.jackrabbit jackrabbit-api - 1.5.0 + 2.6.0 provided Added: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java?rev=1534058&view=auto ============================================================================== --- sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java (added) +++ sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java Mon Oct 21 08:12:07 2013 @@ -0,0 +1,88 @@ +/* + * 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 users = Collections.singleton(PROP_GROUPS_DEFAULT_USER); + + protected Set groups = Collections.emptySet(); + + /** + * Handle configuration + * @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary) + */ + public void updated(final Dictionary 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 toSet(final Object configObj, final String defaultUser) { + final Set groups = new HashSet(); + 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; + } +} Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/AbstractWebConsoleSecurityProvider.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java?rev=1534058&view=auto ============================================================================== --- sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java (added) +++ sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java Mon Oct 21 08:12:07 2013 @@ -0,0 +1,42 @@ +/* + * 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.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + private ServicesListener listener; + + /** + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(final BundleContext context) throws Exception { + listener = new ServicesListener(context); + } + + /** + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(final BundleContext context) throws Exception { + if ( listener != null ) { + listener.deactivate(); + listener = null; + } + } +} Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/Activator.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java?rev=1534058&view=auto ============================================================================== --- sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java (added) +++ sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java Mon Oct 21 08:12:07 2013 @@ -0,0 +1,275 @@ +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 javax.jcr.Repository; + +import org.apache.felix.webconsole.WebConsoleSecurityProvider; +import org.apache.sling.auth.core.AuthenticationSupport; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.cm.ManagedService; + +/** + * The ServicesListener listens for the required services + * and registers the security provider when required services are available + */ +public class ServicesListener { + + /** The bundle context. */ + private final BundleContext bundleContext; + + /** The listener for the repository. */ + private final Listener repositoryListener; + + /** The listener for the authentication support. */ + private final Listener authSupportListener; + + private final SlingWebConsoleSecurityProvider provider = new SlingWebConsoleSecurityProvider(); + + private final SlingWebConsoleSecurityProvider2 provider2 = new SlingWebConsoleSecurityProvider2(); + + private enum State { + NONE, + PROVIDER, + PROVIDER2 + }; + + /** State */ + private volatile State registrationState = State.NONE; + + /** The registration for the provider */ + private ServiceRegistration providerReg; + + /** The registration for the provider2 */ + private ServiceRegistration provider2Reg; + + + /** + * Start listeners + */ + public ServicesListener(final BundleContext bundleContext) { + this.bundleContext = bundleContext; + this.authSupportListener = new Listener(AuthenticationSupport.class.getName()); + this.repositoryListener = new Listener(Repository.class.getName()); + this.authSupportListener.start(); + this.repositoryListener.start(); + } + + /** + * Notify of service changes from the listeners. + */ + public synchronized void notifyChange() { + // check if all services are available + final AuthenticationSupport authSupport = (AuthenticationSupport)this.authSupportListener.getService(); + final Repository repository = (Repository)this.repositoryListener.getService(); + if ( registrationState == State.NONE ) { + if ( authSupport != null ) { + registerProvider2(authSupport); + } else if ( repository != null ) { + registerProvider(repository); + } + } else if ( registrationState == State.PROVIDER ) { + if ( authSupport != null ) { + registerProvider2(authSupport); + unregisterProvider(); + } else if ( repository == null ) { + unregisterProvider(); + this.registrationState = State.NONE; + } else { + this.provider.setService(repository); + } + } else { + if ( authSupport == null ) { + if ( repository != null ) { + registerProvider(repository); + } else { + this.registrationState = State.NONE; + } + unregisterProvider2(); + } else { + this.provider2.setService(authSupport); + } + } + } + + private void unregisterProvider2() { + if ( this.provider2Reg != null ) { + this.provider2Reg.unregister(); + this.provider2Reg = null; + } + this.provider2.setService(null); + } + + private void unregisterProvider() { + if ( this.providerReg != null ) { + this.providerReg.unregister(); + this.providerReg = null; + } + this.provider.setService(null); + } + + private void registerProvider2(final AuthenticationSupport authSupport) { + this.provider2.setService(authSupport); + final Dictionary 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"); + this.provider2Reg = this.bundleContext.registerService( + new String[] {ManagedService.class.getName(), WebConsoleSecurityProvider.class.getName()}, this.provider2, props); + this.registrationState = State.PROVIDER2; + } + + private void registerProvider(final Repository repository) { + this.provider.setService(repository); + final Dictionary 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"); + this.providerReg = this.bundleContext.registerService( + new String[] {ManagedService.class.getName(), WebConsoleSecurityProvider.class.getName()}, this.provider, props); + this.registrationState = State.PROVIDER; + } + + /** + * Deactivate this listener. + */ + public void deactivate() { + this.repositoryListener.deactivate(); + this.authSupportListener.deactivate(); + this.unregisterProvider(); + this.unregisterProvider2(); + } + + /** + * Helper class listening for service events for a defined service. + */ + protected final class Listener implements ServiceListener { + + /** The name of the service. */ + private final String serviceName; + + /** The service reference. */ + private volatile ServiceReference reference; + + /** The service. */ + private volatile Object service; + + /** + * Constructor + */ + public Listener(final String serviceName) { + this.serviceName = serviceName; + } + + /** + * Start the listener. + * First register a service listener and then check for the service. + */ + public void start() { + try { + bundleContext.addServiceListener(this, "(" + + Constants.OBJECTCLASS + "=" + serviceName + ")"); + } catch (final InvalidSyntaxException ise) { + // this should really never happen + throw new RuntimeException("Unexpected exception occured.", ise); + } + final ServiceReference ref = bundleContext.getServiceReference(serviceName); + if ( ref != null ) { + this.retainService(ref); + } + } + + /** + * Unregister the listener. + */ + public void deactivate() { + bundleContext.removeServiceListener(this); + } + + /** + * Return the service (if available) + */ + public synchronized Object getService() { + return this.service; + } + + /** + * Try to get the service and notify the change. + */ + private synchronized void retainService(final ServiceReference ref) { + boolean hadService = this.service != null; + boolean getService = this.reference == null; + if ( !getService ) { + final int result = this.reference.compareTo(ref); + if ( result < 0 ) { + bundleContext.ungetService(this.reference); + this.service = null; + getService = true; + } + } + if ( getService ) { + this.reference = ref; + this.service = bundleContext.getService(this.reference); + if ( this.service == null ) { + this.reference = null; + } else { + notifyChange(); + } + } + if ( hadService && this.service == null ) { + notifyChange(); + } + } + + /** + * Try to release the service and notify the change. + */ + private synchronized void releaseService(final ServiceReference ref) { + if ( this.reference != null && this.reference.compareTo(ref) == 0) { + this.service = null; + bundleContext.ungetService(this.reference); + this.reference = null; + notifyChange(); + } + } + + /** + * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent) + */ + public void serviceChanged(final ServiceEvent event) { + if (event.getType() == ServiceEvent.REGISTERED) { + this.retainService(event.getServiceReference()); + } else if ( event.getType() == ServiceEvent.UNREGISTERING ) { + this.releaseService(event.getServiceReference()); + } else if ( event.getType() == ServiceEvent.MODIFIED ) { + notifyChange(); + } + } + } +} Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/ServicesListener.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider.java?rev=1534058&r1=1534057&r2=1534058&view=diff ============================================================================== --- sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider.java (original) +++ sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider.java Mon Oct 21 08:12:07 2013 @@ -18,33 +18,22 @@ */ package org.apache.sling.extensions.webconsolesecurityprovider.internal; -import java.util.Collection; -import java.util.HashSet; import java.util.Iterator; -import java.util.Map; -import java.util.Set; import javax.jcr.Credentials; import javax.jcr.LoginException; import javax.jcr.Repository; -import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.SimpleCredentials; -import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.Modified; +import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; -import org.apache.felix.scr.annotations.Reference; -import org.apache.felix.scr.annotations.Service; -import org.apache.felix.webconsole.WebConsoleSecurityProvider; 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.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The SlingWebConsoleSecurityProvider is security provider for the @@ -58,42 +47,35 @@ import org.slf4j.LoggerFactory; * only registered as a security provider service once such a JCR Repository is * available. */ -@Component(specVersion = "1.1", metatype = true) -@Service(WebConsoleSecurityProvider.class) -public class SlingWebConsoleSecurityProvider implements - WebConsoleSecurityProvider { +@Component(ds=false, metatype=true, + label="Apache Sling Web Console Security Provider", + description="Configuration for the security provider used to verfiy user " + + "credentials and grant access to the Apache Felix Web Console " + + "based on registered JCR Repository users.") +@Properties({ + @Property(name = "users", value=AbstractWebConsoleSecurityProvider.PROP_GROUPS_DEFAULT_USER, cardinality=20, + label="User Names", + description="Names of users granted full access to the Apache Felix " + + "Web Console. By default this lists the \"admin\" user. A maximum of 20 users" + + " may be configured. Administrators are encouraged to create a group whose" + + " members are to be granted access to Web Console instead of allowing access" + + " to individual users."), + @Property(name = "groups", cardinality=20, + label="Group Names", + description="Names of groups whose members are granted full access to the Apache Felix " + + "Web Console. The default lists no groups. Administrators are encouraged to " + + "create a group whose members are to be granted access to the Web Console." + + " A maximum of 20 groups may be configured. Using groups to control" + + " access requires a Jackrabbit based repository.") +}) +public class SlingWebConsoleSecurityProvider extends AbstractWebConsoleSecurityProvider { - // name of the property providing list of authorized users - private static final String PROP_USERS = "users"; - - // default user being authorized - private 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 log */ - private final Logger log = LoggerFactory.getLogger(getClass()); - - @Reference private Repository repository; - @Property(name = PROP_USERS, cardinality = 20, value = PROP_GROUPS_DEFAULT_USER) - private Set users; - - @Property(name = PROP_GROUPS, cardinality = 20) - private Set groups; - - // ---------- SCR integration - - @SuppressWarnings("unused") - @Activate - @Modified - private void configure(Map config) { - this.users = toSet(config.get(PROP_USERS)); - this.groups = toSet(config.get(PROP_GROUPS)); + public void setService(final Repository repo) { + this.repository = repo; } + // ---------- SCR integration /** * Authenticates and authorizes the user identified by the user name and @@ -148,27 +130,27 @@ public class SlingWebConsoleSecurityProv } } - log.info( - "authenticate: User {} is granted Web Console access", + logger.debug( + "authenticate: User {} is denied Web Console access", userName); } else { - log.error( + logger.error( "authenticate: Expected user ID {} to refer to a user", userId); } } else { - log.info( + logger.info( "authenticate: Jackrabbit Session required to grant access to the Web Console for {}; got {}", userName, session.getClass()); } - } catch (LoginException re) { - log.info( + } catch (final LoginException re) { + logger.info( "authenticate: User " + userName + " failed to authenticate with the repository for Web Console access", re); - } catch (Exception re) { - log.info("authenticate: Generic problem trying grant User " + } catch (final Exception re) { + logger.info("authenticate: Generic problem trying grant User " + userName + " access to the Web Console", re); } finally { if (session != null) { @@ -185,27 +167,7 @@ public class SlingWebConsoleSecurityProv * authorized groups are granted access for all roles in the Web Console. */ public boolean authorize(Object user, String role) { - log.info("authorize: Grant user {} access for role {}", user, role); + logger.debug("authorize: Grant user {} access for role {}", user, role); return true; } - - private Set toSet(final Object configObj) { - final HashSet groups = new HashSet(); - 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); - } - } - } - return groups; - } } Added: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java?rev=1534058&view=auto ============================================================================== --- sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java (added) +++ sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java Mon Oct 21 08:12:07 2013 @@ -0,0 +1,145 @@ +/* + * 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.Iterator; + +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.felix.webconsole.WebConsoleSecurityProvider2; +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.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.auth.core.AuthenticationSupport; + +/** + * The SlingWebConsoleSecurityProvider is security provider for the + * Apache Felix Web Console which validates the user name and password by loging + * into the repository and the checking whether the user is allowed access. + * Access granted by the {@link #authenticate(String, String)} method applies to + * all of the Web Console since the {@link #authorize(Object, String)} method + * always returns true. + *

+ * This security provider requires a JCR Repository to operate. Therefore it is + * only registered as a security provider service once such a JCR Repository is + * available. + */ +public class SlingWebConsoleSecurityProvider2 + extends AbstractWebConsoleSecurityProvider + implements WebConsoleSecurityProvider2 { + + private AuthenticationSupport authenticator; + + public void setService(final AuthenticationSupport support) { + this.authenticator = support; + } + + private void invokeAuthenticator(final HttpServletRequest request, final HttpServletResponse response) { + final AuthenticationSupport localAuthenticator = this.authenticator; + if (localAuthenticator != null) { + localAuthenticator.handleSecurity(request, response); + } + } + + /** + * @see org.apache.felix.webconsole.WebConsoleSecurityProvider2#authenticate(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public boolean authenticate(final HttpServletRequest request, + final HttpServletResponse response) { + invokeAuthenticator(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; + } + return false; + } catch (final Exception re) { + logger.info("authenticate: Generic problem trying grant User " + + " access to the Web Console", re); + } + } + } + return false; + } + + public User authenticate(String userName, String password) { + return null; // this method is never invoked + } + + private User authenticate(final Session session) throws RepositoryException { + String userId = session.getUserID(); + if (session instanceof JackrabbitSession) { + UserManager umgr = ((JackrabbitSession) session).getUserManager(); + Authorizable a = umgr.getAuthorizable(userId); + if (a instanceof User) { + + // check users + if (users.contains(userId)) { + return (User)a; + } + + // check groups + @SuppressWarnings("unchecked") + Iterator gi = a.memberOf(); + while (gi.hasNext()) { + if (groups.contains(gi.next().getID())) { + return (User)a; + } + } + + logger.info( + "authenticate: User {} is denied Web Console access", + userId); + } else { + logger.error( + "authenticate: Expected user ID {} to refer to a user", + userId); + } + } else { + logger.info( + "authenticate: Jackrabbit Session required to grant access to the Web Console for {}; got {}", + userId, session.getClass()); + } + 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. + */ + public boolean authorize(Object user, String role) { + logger.debug("authorize: Grant user {} access for role {}", user, role); + return true; + } +} Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url Propchange: sling/trunk/bundles/extensions/webconsolesecurityprovider/src/main/java/org/apache/sling/extensions/webconsolesecurityprovider/internal/SlingWebConsoleSecurityProvider2.java ------------------------------------------------------------------------------ svn:mime-type = text/plain