All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xlcloud.console.context.AccessEngineClientImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2012 AMG.lab, a Bull Group Company
 * 
 * Licensed 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.xlcloud.console.context;

import java.io.Serializable;
import java.security.AccessController;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.core.Cookie;

import org.apache.log4j.Logger;
import org.xlcloud.config.ConfigParam;
import org.xlcloud.console.context.exceptions.SSOUserTokenInvalidException;
import org.xlcloud.console.performance.AccessEnginePerformanceMonitoring;
import org.xlcloud.logging.LoggingUtils;
import org.xlcloud.rest.exception.InternalErrorException;
import org.xlcloud.service.HttpAction;

import com.iplanet.sso.SSOException;
import com.iplanet.sso.SSOToken;
import com.iplanet.sso.SSOTokenManager;
import com.sun.identity.policy.ActionDecision;
import com.sun.identity.policy.NameNotFoundException;
import com.sun.identity.policy.Policy;
import com.sun.identity.policy.PolicyDecision;
import com.sun.identity.policy.PolicyException;
import com.sun.identity.policy.PolicyManager;
import com.sun.identity.policy.ResourceMatch;
import com.sun.identity.policy.Rule;
import com.sun.identity.policy.client.PolicyEvaluator;
import com.sun.identity.policy.client.PolicyEvaluatorFactory;
import com.sun.identity.security.AMSecurityPropertiesException;
import com.sun.identity.security.AdminTokenAction;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

/**
 * Engine responsible for checking access permission basing on user's
 * entitlements stored in OpenAM. Uses OpenAM's client-sdk so that all
 * evaluations are performed locally (and not in OpenAM)
 * 
 * @author Jakub Wachowski, AMG.net
 */
@AccessEnginePerformanceMonitoring
public class AccessEngineClientImpl implements AccessEngineClient, Serializable {

    private static final long serialVersionUID = -707771051501050598L;

    private static final Logger LOG = Logger.getLogger(AccessEngineClientImpl.class);

    private static final Set ALL_ACTIONS;
    static {
        Set actions = new HashSet<>();
        for (HttpAction ha : HttpAction.values()) {
            actions.add(ha.value());
        }
        ALL_ACTIONS = Collections.unmodifiableSet(actions);
    }

    @Inject
    @ConfigParam
    private String realm;

    @Inject
    @ConfigParam
    private String accessTokenValidatorUrl;

    @Inject
    @AccessEngineRestClient
    private Client client;

    private PolicyManager policyManager;
    
    @PostConstruct
    public void init(){
        LOG.debug("Using Jersey client " + client.hashCode());
    }

    /** {@inheritDoc} */
    @Override
    public boolean hasAccess(SSOToken userToken, HttpAction action, String path) {
        if (LOG.isTraceEnabled()) {
            LOG.trace("asserting access for: " + action.value() + " : " + path);
        }

        try {
            Set allowedActions = getAllowedActions(userToken, path);
            boolean hasAccess = allowedActions.contains(action.value());
            if (LOG.isDebugEnabled()) {
                LOG.debug("Access validation for token [" + LoggingUtils.maskPartially("" + userToken.getTokenID()) + "] and resource ["
                        + action.value() + " : " + LoggingUtils.maskResource(path) + "]: " + (hasAccess ? "allowed" : "denied"));
            }
            return hasAccess;
        } catch (PolicyException e) {
            validateUserToken(userToken);

            LOG.error(e.getMessage(), e);
            throw new RuntimeException(e);
        } catch (SSOException e) {
            validateUserToken(userToken);

            LOG.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    /** {@inheritDoc} */
    @Override
    public boolean subjectHasAccess(String policyName, HttpAction action, String path) {
        try {
            if (policyManager == null) {
                policyManager = new PolicyManager(getAppSSOToken(), realm);
            }
            Policy p = policyManager.getPolicy(policyName);
            @SuppressWarnings( "unchecked" )
            Set ruleNames = p.getRuleNames();

            for (String ruleName : ruleNames) {
                Rule r = p.getRule(ruleName);
                if (ruleResourceMatches(r, path)) {
                    @SuppressWarnings( "unchecked" )
                    Map> actions = r.getActionValues();
                    Set a = actions.get(action.value());
                    if (a != null && a.size() == 1 && "allow".equals(a.iterator().next())) {
                        return true;
                    }
                }

            }

        } catch (NameNotFoundException e) {
            // TODO: if policy does not exists return false (subject does not
            // have access)
            // LOG.error(e.getMessage(), e);
            // throw new RuntimeException(e);
        } catch (SSOException e) {
            LOG.error(e.getMessage(), e);
            throw new RuntimeException(e);
        } catch (PolicyException e) {
            LOG.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }

        return false;
    }

    /**
     * Returns current application sso token
     * 
     * @return application sso token
     */
    public synchronized static SSOToken getAppSSOToken() {
        // always ensure token is valid - after OpenAM restart it may be invalid
        return getAppSSOToken(true);
    }

    /**
     * @param r
     * @param path
     * @return
     */
    private boolean ruleResourceMatches(Rule r, String path) {
        ResourceMatch rm = r.isResourceMatch("xlcRestAppl", path);
        if (ResourceMatch.EXACT_MATCH.equals(rm) || ResourceMatch.WILDCARD_MATCH.equals(rm)) {
            return true;
        }
        return false;
    }

    private static SSOToken getAppSSOToken(boolean refresh) {
        SSOToken appToken = null;

        try {
            appToken = (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());
        } catch (AMSecurityPropertiesException aspe) {
            String message = "Unable to create an application token";
            throw new RuntimeException(message, aspe);
        }

        if (refresh) {
            // ensure the token is valid
            try {
                SSOTokenManager ssoTokenManager = SSOTokenManager.getInstance();
                ssoTokenManager.refreshSession(appToken);

                if (!ssoTokenManager.isValidToken(appToken)) {
                    try {
                        appToken = (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());
                    } catch (AMSecurityPropertiesException aspe) {
                        String message = "Unable to create an application token";
                        throw new RuntimeException(message, aspe);
                    }
                }
            } catch (SSOException ssoe) {
                try {
                    appToken = (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());
                } catch (AMSecurityPropertiesException aspe) {
                    String message = "Unable to create an application token";
                    throw new RuntimeException(message, aspe);
                }
            }
        }

        return appToken;
    }

    @SuppressWarnings( "unchecked" )
    private Set getAllowedActions(SSOToken token, String path) throws PolicyException, SSOException {
        PolicyEvaluator pe = PolicyEvaluatorFactory.getInstance().getPolicyEvaluator("xlcRestAppl");
        // due to problems with caching in ClientSDK, always evaluate access for
        // all actions
        PolicyDecision pd = pe.getPolicyDecision(token, path, ALL_ACTIONS);

        Set allowedActions = new HashSet();

        Map actionDecisions = pd.getActionDecisions();

        if (pd.getActionDecisions() != null) {
            for (ActionDecision ad : actionDecisions.values()) {
                String actionName = ad.getActionName();
                Set actions = ad.getValues();
                if (actions != null && actions.size() == 1 && "allow".equals(actions.iterator().next())) {
                    allowedActions.add(actionName);
                }
            }
        }
        return allowedActions;
    }

    /**
     * It validates given user token and throws
     * {@link SSOUserTokenInvalidException} if token is invalid.
     * 
     * @param userToken
     *            user token to be validated.
     * @throws SSOUserTokenInvalidException
     *             thrown if the token is invalid.
     */
    private void validateUserToken(SSOToken userToken) throws SSOUserTokenInvalidException {
        try {
            if (!SSOTokenManager.getInstance().isValidToken(userToken)) {
                throw new SSOUserTokenInvalidException("User's SSO token is invalid.");
            }
        } catch (SSOException e) {
            // SSOException may occur if SSOTokenManager.getInstance() failed,
            // then we are unable to validate user token.
            LOG.error(e, e);
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    public boolean isTokenValid(String accessToken) {
        WebResource resource = client.resource(accessTokenValidatorUrl + "/" + accessToken);
        ClientResponse response = resource.cookie(new Cookie("iPlanetDirectoryPro", getAppSSOToken().getTokenID().toString())).get(
                ClientResponse.class);

        // OpenAM should return '200 OK' code
        if (response.getStatus() != ClientResponse.Status.OK.getStatusCode()) {
            // if status code is 404 - it means that token id was incorrect
            if (ClientResponse.Status.NOT_FOUND.equals(response.getClientResponseStatus())) {
                LOG.debug("Token with id [" + LoggingUtils.maskPartially(accessToken) + "] not found in the repository");
                return false;
            }
            LOG.debug("En error occured when validate token with id [" + LoggingUtils.maskPartially(accessToken) + "], exception: HTTP: "
                    + response.getStatus() + ", " + response.getEntity(String.class));
            throw new InternalErrorException("Could not validate " + LoggingUtils.maskPartially(accessToken),InternalErrorException.ErrorType.OPENAM);
        } else {
            return true;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy