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

io.vertigo.account.impl.authorization.AuthorizationManagerImpl Maven / Gradle / Ivy

The newest version!
/*
 * vertigo - application development platform
 *
 * Copyright (C) 2013-2024, Vertigo.io, [email protected]
 *
 * 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 io.vertigo.account.impl.authorization;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.inject.Inject;

import io.vertigo.account.authorization.AuthorizationManager;
import io.vertigo.account.authorization.UserAuthorizations;
import io.vertigo.account.authorization.definitions.Authorization;
import io.vertigo.account.authorization.definitions.AuthorizationName;
import io.vertigo.account.authorization.definitions.OperationName;
import io.vertigo.account.authorization.definitions.SecuredEntity;
import io.vertigo.account.authorization.definitions.rulemodel.RuleMultiExpression;
import io.vertigo.account.impl.authorization.dsl.translator.CriteriaSecurityRuleTranslator;
import io.vertigo.account.impl.authorization.dsl.translator.SearchSecurityRuleTranslator;
import io.vertigo.account.security.UserSession;
import io.vertigo.account.security.VSecurityManager;
import io.vertigo.core.lang.Assertion;
import io.vertigo.core.node.Node;
import io.vertigo.datamodel.criteria.Criteria;
import io.vertigo.datamodel.criteria.Criterions;
import io.vertigo.datamodel.data.definitions.DataDefinition;
import io.vertigo.datamodel.data.model.Entity;
import io.vertigo.datamodel.data.util.DataModelUtil;

/**
 * Main authorizations manager implementation.
 * @author npiedeloup
 */
public final class AuthorizationManagerImpl implements AuthorizationManager {
	private static final String USER_SESSION_ACL_KEY = "vertigo.account.authorizations";

	private final VSecurityManager securityManager;

	/**
	 * Constructor.
	 * @param securityManager Security manager
	 */
	@Inject
	public AuthorizationManagerImpl(final VSecurityManager securityManager) {
		Assertion.check().isNotNull(securityManager);
		//-----
		this.securityManager = securityManager;
	}

	/** {@inheritDoc} */
	@Override
	public UserAuthorizations obtainUserAuthorizations() {
		return getUserAuthorizationsOpt().orElseThrow(() -> new IllegalArgumentException("Can't getUserAuthorizations, check your have create an UserSession before."));

	}

	private Optional getUserAuthorizationsOpt() {
		final Optional userSessionOpt = securityManager.getCurrentUserSession();
		if (userSessionOpt.isEmpty()) {
			// Si il n'y a pas de session alors pas d'autorisation.
			return Optional.empty();
		}
		UserAuthorizations userAuthorizations = userSessionOpt.get().getAttribute(USER_SESSION_ACL_KEY);
		if (userAuthorizations == null) {
			userAuthorizations = new UserAuthorizations();
			userSessionOpt.get().putAttribute(USER_SESSION_ACL_KEY, userAuthorizations);
		}
		return Optional.of(userAuthorizations);

	}

	/** {@inheritDoc} */
	@Override
	public boolean hasAuthorization(final AuthorizationName... permissionNames) {
		Assertion.check().isNotNull(permissionNames);
		//may check authorizationNames exists to prevent badly names
		//---
		return getUserAuthorizationsOpt()
				.map(userPermissions -> userPermissions.hasAuthorization(permissionNames))
				// Si il n'y a pas de userPermissions alors pas d'autorisation.
				.orElse(false);

	}

	/** {@inheritDoc} */
	@Override
	public  boolean isAuthorized(final E entity, final OperationName operationName) {
		Assertion.check().isNotNull(entity)
				.isNotNull(operationName);
		//---
		final Optional userPermissionsOpt = getUserAuthorizationsOpt();
		if (userPermissionsOpt.isEmpty()) {
			// Si il n'y a pas de session alors pas d'autorisation.
			return false;
		}
		final UserAuthorizations userPermissions = userPermissionsOpt.get();
		final DataDefinition dataDefinition = DataModelUtil.findDataDefinition(entity);
		final SecuredEntity securedEntity = findSecuredEntity(dataDefinition);
		final Optional authorization = userPermissions.getEntityAuthorizations(dataDefinition).stream()
				.filter(permission -> permission.getOperation().orElse("").equals(operationName.name())
						|| permission.getOverrides().contains(operationName.name()))
				.findFirst();
		if (authorization.isEmpty()) {
			// Si il n'y a pas d'authorization pour cette operation ou pour une authorization qui override
			return false;
		}
		return authorization.get().getRules().stream()
				.anyMatch(rule -> new CriteriaSecurityRuleTranslator()
						.on(securedEntity)
						.withRule(rule)
						.withSecurityKeys(userPermissions.getSecurityKeys())
						.toCriteria()
						.toPredicate().test(entity));
	}

	/** {@inheritDoc} */
	@Override
	public  Criteria getCriteriaSecurity(final Class entityClass, final OperationName operation) {
		Assertion.check().isNotNull(entityClass)
				.isNotNull(operation);
		//---
		final DataDefinition dataDefinition = DataModelUtil.findDataDefinition(entityClass);
		final Optional userPermissionsOpt = getUserAuthorizationsOpt();
		if (userPermissionsOpt.isEmpty()) {
			// Si il n'y a pas de session alors pas d'autorisation.
			return Criterions.alwaysFalse();
		}

		final UserAuthorizations userPermissions = userPermissionsOpt.get();
		final SecuredEntity securedEntity = findSecuredEntity(dataDefinition);

		final List> criterions = userPermissions.getEntityAuthorizations(dataDefinition).stream()
				.filter(permission -> permission.getOperation().get().equals(operation.name())
						|| permission.getOverrides().contains(operation.name()))
				.flatMap(permission -> permission.getRules().stream())
				.map(rule -> new CriteriaSecurityRuleTranslator()
						.on(securedEntity)
						.withRule(rule)
						.withSecurityKeys(userPermissions.getSecurityKeys())
						.toCriteria())
				.toList();

		if (criterions.isEmpty()) {
			// Si il n'y a pas de droits alors pas d'autorisation.
			return Criterions.alwaysFalse();
		}

		Criteria securityCriteria = null;
		for (final Criteria ruleCriteria : criterions) {
			if (securityCriteria == null) {
				securityCriteria = ruleCriteria;
			} else {
				securityCriteria = securityCriteria.or(ruleCriteria);
			}
		}
		return securityCriteria;
	}

	/** {@inheritDoc} */
	@Override
	public  String getSearchSecurity(final Class entityClass, final OperationName operationName) {
		Assertion.check()
				.isNotNull(entityClass)
				.isNotNull(operationName);
		//SearchSecurityFilter should check that index contains all security fields
		//---
		final Optional userPermissionsOpt = getUserAuthorizationsOpt();
		if (userPermissionsOpt.isEmpty()) {
			// Si il n'y a pas de session alors pas d'autorisation.
			return ""; //Attention : pas de *:*
		}

		final DataDefinition dataDefinition = DataModelUtil.findDataDefinition(entityClass);
		final SecuredEntity securedEntity = findSecuredEntity(dataDefinition);

		final UserAuthorizations userPermissions = userPermissionsOpt.get();
		final SearchSecurityRuleTranslator securityRuleTranslator = new SearchSecurityRuleTranslator()
				.on(securedEntity)
				.withSecurityKeys(userPermissions.getSecurityKeys());

		final List permissions = userPermissions.getEntityAuthorizations(dataDefinition).stream()
				.filter(permission -> permission.getOperation().get().equals(operationName.name())
						|| permission.getOverrides().contains(operationName.name()))
				.toList();

		if (permissions.isEmpty()) {
			// Si il n'y a pas d'autorisation.
			return ""; //Attention : pas de *:*
		}

		for (final Authorization permission : permissions) {
			for (final RuleMultiExpression ruleExpression : permission.getRules()) {
				securityRuleTranslator.withRule(ruleExpression);
			}
		}
		return securityRuleTranslator.toSearchQuery();
	}

	@Override
	public Set getPriorAuthorizations() {
		return getUserAuthorizationsOpt()
				.map(UserAuthorizations::getPriorAuthorizationNames)
				// Si il n'y a pas de userPermissions alors pas d'autorisation.
				.orElseGet(Collections::emptySet);
	}

	/** {@inheritDoc} */
	@Override
	public  Set getAuthorizedOperations(final E entity) {
		Assertion.check().isNotNull(entity);
		//---
		final Optional userPermissionsOpt = getUserAuthorizationsOpt();
		if (userPermissionsOpt.isEmpty()) {
			// Si il n'y a pas de session alors pas d'autorisation.
			return Collections.emptySet();
		}
		final UserAuthorizations userPermissions = userPermissionsOpt.get();
		final DataDefinition dataDefinition = DataModelUtil.findDataDefinition(entity);
		final SecuredEntity securedEntity = findSecuredEntity(dataDefinition);

		return userPermissions.getEntityAuthorizations(dataDefinition).stream()
				.filter(permission -> permission.getRules().stream()
						.anyMatch(rule -> new CriteriaSecurityRuleTranslator()
								.on(securedEntity)
								.withRule(rule)
								.withSecurityKeys(userPermissions.getSecurityKeys())
								.toCriteria()
								.toPredicate().test(entity)))
				.flatMap(authorization -> Stream.concat(Stream.of(authorization.getOperation().get()), authorization.getOverrides().stream()))
				.collect(Collectors.toSet());
	}

	/**
	 * Finds the SecuredEntity from a type of 'dataDefinition'
	 * @param dataDefinition the 'dataDefinition'
	 * @return SecuredEntity
	 */
	public static SecuredEntity findSecuredEntity(final DataDefinition dataDefinition) {
		Assertion.check().isNotNull(dataDefinition);
		//---
		final String name = SecuredEntity.PREFIX + dataDefinition.getName();
		return Node.getNode().getDefinitionSpace().resolve(name, SecuredEntity.class);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy