Package org.apache.syncope.core.security

Source Code of org.apache.syncope.core.security.SyncopeAuthenticationProvider

/*
* 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.syncope.core.security;

import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import javax.annotation.Resource;
import org.apache.syncope.common.types.AttributableType;
import org.apache.syncope.common.types.AuditElements;
import org.apache.syncope.common.types.AuditElements.Result;
import org.apache.syncope.common.types.CipherAlgorithm;
import org.apache.syncope.core.audit.AuditManager;
import org.apache.syncope.core.persistence.beans.AccountPolicy;
import org.apache.syncope.core.persistence.beans.ExternalResource;
import org.apache.syncope.core.persistence.beans.conf.CAttr;
import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
import org.apache.syncope.core.persistence.dao.ConfDAO;
import org.apache.syncope.core.persistence.dao.PolicyDAO;
import org.apache.syncope.core.persistence.dao.UserDAO;
import org.apache.syncope.core.propagation.ConnectorFactory;
import org.apache.syncope.core.util.AttributableUtil;
import org.apache.syncope.core.util.Encryptor;
import org.apache.syncope.core.util.MappingUtil;
import org.identityconnectors.framework.common.objects.Uid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.transaction.annotation.Transactional;

@Configurable
public class SyncopeAuthenticationProvider implements AuthenticationProvider {

    /**
     * Logger.
     */
    protected static final Logger LOG = LoggerFactory.getLogger(SyncopeAuthenticationProvider.class);

    @Autowired
    private AuditManager auditManager;

    @Autowired
    private ConfDAO confDAO;

    @Autowired
    private UserDAO userDAO;

    @Autowired
    private PolicyDAO policyDAO;

    @Autowired
    private ConnectorFactory connFactory;

    @Resource(name = "adminUser")
    private String adminUser;

    @Resource(name = "anonymousUser")
    private String anonymousUser;

    private String adminPassword;

    private String adminPasswordAlgorithm;

    private String anonymousKey;

    private SyncopeUserDetailsService userDetailsService;

    private final Encryptor encryptor = Encryptor.getInstance();

    /**
     * @param adminPassword the adminPassword to set
     */
    public void setAdminPassword(final String adminPassword) {
        this.adminPassword = adminPassword;
    }

    /**
     * @param adminPasswordAlgorithm the adminPasswordAlgorithm to set
     */
    public void setAdminPasswordAlgorithm(final String adminPasswordAlgorithm) {
        this.adminPasswordAlgorithm = adminPasswordAlgorithm;
    }

    /**
     * @param anonymousKey the anonymousKey to set
     */
    public void setAnonymousKey(final String anonymousKey) {
        this.anonymousKey = anonymousKey;
    }

    public void setSyncopeUserDetailsService(final SyncopeUserDetailsService syncopeUserDetailsService) {
        this.userDetailsService = syncopeUserDetailsService;
    }

    @Override
    @Transactional(noRollbackFor = { BadCredentialsException.class, DisabledException.class })
    public Authentication authenticate(final Authentication authentication)
            throws AuthenticationException {

        boolean authenticated = false;
        SyncopeUser user = null;

        String username = authentication.getName();
        if (anonymousUser.equals(username)) {
            authenticated = authentication.getCredentials().toString().equals(anonymousKey);
        } else if (adminUser.equals(username)) {
            authenticated = encryptor.verify(
                    authentication.getCredentials().toString(),
                    CipherAlgorithm.valueOf(adminPasswordAlgorithm),
                    adminPassword);
        } else {
            user = userDAO.find(username);

            if (user != null) {
                if (user.isSuspended() != null && user.isSuspended()) {
                    throw new DisabledException("User " + user.getUsername() + " is suspended");
                }

                CAttr authStatuses = confDAO.find("authentication.statuses");
                if (authStatuses != null && !authStatuses.getValuesAsStrings().contains(user.getStatus())) {
                    throw new DisabledException("User " + user.getUsername() + " not allowed to authenticate");
                }

                authenticated = authenticate(user, authentication.getCredentials().toString());

                updateLoginAttributes(user, authenticated);
            }
        }

        UsernamePasswordAuthenticationToken token;
        if (authenticated) {
            token = new UsernamePasswordAuthenticationToken(
                    authentication.getPrincipal(),
                    null,
                    userDetailsService.loadUserByUsername(authentication.getPrincipal().toString()).getAuthorities());

            token.setDetails(authentication.getDetails());

            auditManager.audit(
                    AuditElements.EventCategoryType.REST,
                    "AuthenticationController",
                    null,
                    "login",
                    Result.SUCCESS,
                    null,
                    authenticated,
                    authentication,
                    "Successfully authenticated, with roles: " + token.getAuthorities());

            LOG.debug("User {} successfully authenticated, with roles {}",
                    authentication.getPrincipal(), token.getAuthorities());
        } else {
            auditManager.audit(
                    AuditElements.EventCategoryType.REST,
                    "AuthenticationController",
                    null,
                    "login",
                    Result.FAILURE,
                    null,
                    authenticated,
                    authentication,
                    "User " + authentication.getPrincipal() + " not authenticated");

            LOG.debug("User {} not authenticated", authentication.getPrincipal());

            throw new BadCredentialsException("User " + authentication.getPrincipal() + " not authenticated");
        }

        return token;
    }

    private void updateLoginAttributes(SyncopeUser user, boolean authenticated) {
        boolean userModified = false;

        if (authenticated) {
            if (confDAO.find("log.lastlogindate", Boolean.toString(true)).getValues().get(0).getBooleanValue()) {
                user.setLastLoginDate(new Date());
                userModified = true;
            }

            if (user.getFailedLogins() != 0) {
                user.setFailedLogins(0);
                userModified = true;
            }
        } else {
            user.setFailedLogins(user.getFailedLogins() + 1);
            userModified = true;
        }

        if (userModified) {
            userDAO.save(user);
        }
    }

    protected Set<ExternalResource> getPassthroughResources(final SyncopeUser user) {
        Set<ExternalResource> result = null;

        // 1. look for directly assigned resources, pick the ones whose account policy has authentication resources
        for (ExternalResource resource : user.getOwnResources()) {
            if (resource.getAccountPolicy() != null && !resource.getAccountPolicy().getResources().isEmpty()) {
                if (result == null) {
                    result = resource.getAccountPolicy().getResources();
                } else {
                    result.retainAll(resource.getAccountPolicy().getResources());
                }
            }
        }

        // 2. look for owned roles, pick the ones whose account policy has authentication resources
        for (SyncopeRole role : user.getRoles()) {
            if (role.getAccountPolicy() != null && !role.getAccountPolicy().getResources().isEmpty()) {
                if (result == null) {
                    result = role.getAccountPolicy().getResources();
                } else {
                    result.retainAll(role.getAccountPolicy().getResources());
                }
            }
        }

        // 3. look for global account policy (if defined)
        AccountPolicy global = policyDAO.getGlobalAccountPolicy();
        if (global != null && !global.getResources().isEmpty()) {
            if (result == null) {
                result = global.getResources();
            } else {
                result.retainAll(global.getResources());
            }
        }

        if (result == null) {
            result = Collections.emptySet();
        }

        return result;
    }

    protected boolean authenticate(final SyncopeUser user, final String password) {
        boolean authenticated = encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword());
        LOG.debug("{} authenticated on internal storage: {}", user.getUsername(), authenticated);

        final AttributableUtil attrUtil = AttributableUtil.getInstance(AttributableType.USER);
        for (Iterator<ExternalResource> itor = getPassthroughResources(user).iterator();
                itor.hasNext() && !authenticated;) {

            ExternalResource resource = itor.next();
            String accountId = null;
            try {
                accountId = MappingUtil.getAccountIdValue(user, resource, attrUtil.getAccountIdItem(resource));
                Uid uid = connFactory.getConnector(resource).authenticate(accountId, password, null);
                if (uid != null) {
                    authenticated = true;
                }
            } catch (Exception e) {
                LOG.debug("Could not authenticate {} on {}", user.getUsername(), resource.getName(), e);
            }
            LOG.debug("{} authenticated on {} as {}: {}",
                    user.getUsername(), resource.getName(), accountId, authenticated);
        }

        return authenticated;
    }

    @Override
    public boolean supports(final Class<? extends Object> type) {
        return type.equals(UsernamePasswordAuthenticationToken.class);
    }
}
TOP

Related Classes of org.apache.syncope.core.security.SyncopeAuthenticationProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.