/* * 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.isis.core.runtime.authentication.standard; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.isis.applib.annotation.Programmatic; import org.apache.isis.core.commons.authentication.AuthenticationSession; import org.apache.isis.core.commons.config.IsisConfiguration; import org.apache.isis.core.commons.exceptions.IsisException; import org.apache.isis.core.commons.util.ToString; import org.apache.isis.core.metamodel.deployment.DeploymentCategory; import org.apache.isis.core.runtime.authentication.AuthenticationManager; import org.apache.isis.core.runtime.authentication.AuthenticationRequest; import org.apache.isis.core.runtime.authentication.RegistrationDetails; public class AuthenticationManagerStandard implements AuthenticationManager { private final Map<String, String> userByValidationCode = Maps.newHashMap(); private final List<Authenticator> authenticators = Lists.newArrayList(); private RandomCodeGenerator randomCodeGenerator; private final IsisConfiguration configuration; public AuthenticationManagerStandard(final IsisConfiguration configuration) { this.configuration = configuration; } // ////////////////////////////////////////////////////////// // init // ////////////////////////////////////////////////////////// /** * Will default the {@link #setRandomCodeGenerator(RandomCodeGenerator) * RandomCodeGenerator}, but {@link Authenticator}(s) must have been * {@link #addAuthenticator(Authenticator) added}. * @param deploymentCategory */ @Programmatic public final void init(final DeploymentCategory deploymentCategory) { defaultRandomCodeGeneratorIfNecessary(); addDefaultAuthenticators(); if (authenticators.size() == 0) { throw new IsisException("No authenticators specified"); } for (final Authenticator authenticator : authenticators) { authenticator.init(deploymentCategory); } } private void defaultRandomCodeGeneratorIfNecessary() { if (randomCodeGenerator == null) { randomCodeGenerator = new RandomCodeGenerator10Chars(); } } /** * optional hook method */ protected void addDefaultAuthenticators() { } @Programmatic public void shutdown() { for (final Authenticator authenticator : authenticators) { authenticator.shutdown(); } } // ////////////////////////////////////////////////////////// // Session Management (including authenticate) // ////////////////////////////////////////////////////////// @Programmatic @Override public synchronized final AuthenticationSession authenticate(final AuthenticationRequest request) { if (request == null) { return null; } final Collection<Authenticator> compatibleAuthenticators = Collections2.filter(authenticators, AuthenticatorFuncs.compatibleWith(request)); if (compatibleAuthenticators.size() == 0) { throw new NoAuthenticatorException("No authenticator available for processing " + request.getClass().getName()); } for (final Authenticator authenticator : compatibleAuthenticators) { final AuthenticationSession authSession = authenticator.authenticate(request, getUnusedRandomCode()); if (authSession != null) { userByValidationCode.put(authSession.getValidationCode(), authSession.getUserName()); return authSession; } } return null; } private String getUnusedRandomCode() { String code; do { code = randomCodeGenerator.generateRandomCode(); } while (userByValidationCode.containsKey(code)); return code; } @Programmatic @Override public final boolean isSessionValid(final AuthenticationSession session) { final String userName = userByValidationCode.get(session.getValidationCode()); return session.hasUserNameOf(userName); } @Programmatic @Override public void closeSession(final AuthenticationSession session) { List<Authenticator> authenticators = getAuthenticators(); for (Authenticator authenticator : authenticators) { authenticator.logout(session); } userByValidationCode.remove(session.getValidationCode()); } // ////////////////////////////////////////////////////////// // Authenticators // ////////////////////////////////////////////////////////// @Programmatic public final void addAuthenticator(final Authenticator authenticator) { authenticators.add(authenticator); } @Programmatic public void addAuthenticatorToStart(final Authenticator authenticator) { authenticators.add(0, authenticator); } @Programmatic public List<Authenticator> getAuthenticators() { return Collections.unmodifiableList(authenticators); } @Programmatic @Override public boolean register(final RegistrationDetails registrationDetails) { for (final Registrar registrar : getRegistrars()) { if (registrar.canRegister(registrationDetails.getClass())) { return registrar.register(registrationDetails); } } return false; } @Programmatic @Override public boolean supportsRegistration(final Class<? extends RegistrationDetails> registrationDetailsClass) { for (final Registrar registrar : getRegistrars()) { if (registrar.canRegister(registrationDetailsClass)) { return true; } } return false; } @Programmatic public List<Registrar> getRegistrars() { return asAuthenticators(getAuthenticators()); } private static List<Registrar> asAuthenticators(final List<Authenticator> authenticators2) { final List<Registrar> registrars = Lists.transform(authenticators2, Registrar.AS_REGISTRAR_ELSE_NULL); return Lists.newArrayList(Collections2.filter(registrars, Registrar.NON_NULL)); } // ////////////////////////////////////////////////////////// // RandomCodeGenerator // ////////////////////////////////////////////////////////// /** * For injection; will {@link #defaultRandomCodeGeneratorIfNecessary() * default} otherwise. */ @Programmatic public void setRandomCodeGenerator(final RandomCodeGenerator randomCodeGenerator) { assert randomCodeGenerator != null; this.randomCodeGenerator = randomCodeGenerator; } // ////////////////////////////////////////////////////////// // Debugging // ////////////////////////////////////////////////////////// @Override public String toString() { final ToString str = ToString.createAnonymous(this); str.append("authenticators", authenticators.size()); str.append("users", userByValidationCode.size()); return str.toString(); } // ////////////////////////////////////////////////////////// // Injected (constructor) // ////////////////////////////////////////////////////////// protected IsisConfiguration getConfiguration() { return configuration; } }