/**
* Copyright (c) 2014-2016 Evolveum
*
* 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 com.evolveum.midpoint.security.api;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.util.MiscUtil;
import org.apache.lucene.document.Field.Store;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsStorageMethodType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsStorageTypeType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.NonceCredentialsPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordCredentialsPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityQuestionsCredentialsPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType;
/**
* @author Radovan Semancik
*/
public class SecurityUtil {
private static final Trace LOGGER = TraceManager.getTrace(SecurityUtil.class);
/**
* Returns principal representing currently logged-in user. Returns null if the user is anonymous.
*/
public static MidPointPrincipal getPrincipal() throws SecurityViolationException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
SecurityViolationException ex = new SecurityViolationException("No authentication");
LOGGER.error("No authentication", ex);
throw ex;
}
Object principalObject = authentication.getPrincipal();
if (!(principalObject instanceof MidPointPrincipal)) {
if (authentication.getPrincipal() instanceof String && "anonymousUser".equals(principalObject)) {
return null;
} else {
throw new IllegalArgumentException("Expected that spring security principal will be of type "+
MidPointPrincipal.class.getName()+" but it was "+ MiscUtil.getObjectName(principalObject));
}
}
return (MidPointPrincipal) principalObject;
}
public static boolean isAuthenticated() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return (authentication != null);
}
public static Collection<String> getActions(Collection<ConfigAttribute> configAttributes) {
Collection<String> actions = new ArrayList<String>(configAttributes.size());
for (ConfigAttribute attr: configAttributes) {
actions.add(attr.getAttribute());
}
return actions;
}
public static void logSecurityDeny(Object object, String message) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Denied access to {} by {} {}", object, getSubjectDescription(), message);
}
}
public static void logSecurityDeny(Object object, String message, Throwable cause, Collection<String> requiredAuthorizations) {
if (LOGGER.isDebugEnabled()) {
String subjectDesc = getSubjectDescription();
LOGGER.debug("Denied access to {} by {} {}", object, subjectDesc, message);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Denied access to {} by {} {}; one of the following authorization actions is required: "+requiredAuthorizations,
new Object[]{object, subjectDesc, message, cause});
}
}
}
/**
* Returns short description of the subject suitable for log
* and error messages.
* Does not throw errors. Safe to toString-like methods.
* May return null (means anonymous or unknown)
*/
public static String getSubjectDescription() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return null;
}
Object principalObject = authentication.getPrincipal();
if (principalObject == null) {
return null;
}
if (!(principalObject instanceof MidPointPrincipal)) {
return principalObject.toString();
}
return ((MidPointPrincipal)principalObject).getUsername();
}
public static <T> T getCredPolicyItem(CredentialPolicyType defaltCredPolicyType, CredentialPolicyType credPolicyType, Function<CredentialPolicyType, T> getter) {
if (credPolicyType != null) {
T val = getter.apply(credPolicyType);
if (val != null) {
return val;
}
}
if (defaltCredPolicyType != null) {
T val = getter.apply(defaltCredPolicyType);
if (val != null) {
return val;
}
}
return null;
}
public static PasswordCredentialsPolicyType getEffectivePasswordCredentialsPolicy(SecurityPolicyType securityPolicy) {
if (securityPolicy == null) {
return null;
}
CredentialsPolicyType creds = securityPolicy.getCredentials();
if (creds == null) {
return null;
}
if (creds.getDefault() == null) {
return creds.getPassword();
}
PasswordCredentialsPolicyType passPolicy = creds.getPassword();
if (passPolicy == null) {
passPolicy = new PasswordCredentialsPolicyType();
} else {
passPolicy = passPolicy.clone();
}
copyDefaults(creds.getDefault(), passPolicy);
return passPolicy;
}
public static SecurityQuestionsCredentialsPolicyType getEffectiveSecurityQuestionsCredentialsPolicy(SecurityPolicyType securityPolicy) {
if (securityPolicy == null) {
return null;
}
CredentialsPolicyType creds = securityPolicy.getCredentials();
if (creds == null) {
return null;
}
if (creds.getDefault() == null) {
return creds.getSecurityQuestions();
}
SecurityQuestionsCredentialsPolicyType securityQuestionsPolicy = creds.getSecurityQuestions();
if (securityQuestionsPolicy == null) {
securityQuestionsPolicy = new SecurityQuestionsCredentialsPolicyType();
} else {
securityQuestionsPolicy = securityQuestionsPolicy.clone();
}
copyDefaults(creds.getDefault(), securityQuestionsPolicy);
return securityQuestionsPolicy;
}
public static List<NonceCredentialsPolicyType> getEffectiveNonceCredentialsPolicies(SecurityPolicyType securityPolicy) {
if (securityPolicy == null) {
return null;
}
CredentialsPolicyType creds = securityPolicy.getCredentials();
if (creds == null) {
return null;
}
if (creds.getDefault() == null) {
return creds.getNonce();
}
List<NonceCredentialsPolicyType> existingNoncePolicies = creds.getNonce();
List<NonceCredentialsPolicyType> newNoncePolicies = new ArrayList<>(existingNoncePolicies.size());
for(NonceCredentialsPolicyType noncePolicy: existingNoncePolicies) {
NonceCredentialsPolicyType newNoncePolicy = noncePolicy.clone();
copyDefaults(creds.getDefault(), newNoncePolicy);
newNoncePolicies.add(newNoncePolicy);
}
return newNoncePolicies;
}
public static NonceCredentialsPolicyType getEffectiveNonceCredentialsPolicy(SecurityPolicyType securityPolicy) throws SchemaException {
List<NonceCredentialsPolicyType> noncePolies = getEffectiveNonceCredentialsPolicies(securityPolicy);
if (noncePolies.isEmpty()) {
return null;
}
if (noncePolies.size() > 1) {
throw new SchemaException("More than one nonce policy");
}
return noncePolies.get(0);
}
private static void copyDefaults(CredentialPolicyType defaults,
CredentialPolicyType target) {
// Primitive, but efficient
if (target.getHistoryLength() == null && defaults.getHistoryLength() != null) {
target.setHistoryLength(defaults.getHistoryLength());
}
if (target.getHistoryStorageMethod() == null && defaults.getHistoryStorageMethod() != null) {
target.setHistoryStorageMethod(defaults.getHistoryStorageMethod());
}
if (target.getLockoutDuration() == null && defaults.getLockoutDuration() != null) {
target.setLockoutDuration(defaults.getLockoutDuration());
}
if (target.getLockoutFailedAttemptsDuration() == null && defaults.getLockoutFailedAttemptsDuration() != null) {
target.setLockoutFailedAttemptsDuration(defaults.getLockoutFailedAttemptsDuration());
}
if (target.getLockoutMaxFailedAttempts() == null && defaults.getLockoutMaxFailedAttempts() != null) {
target.setLockoutMaxFailedAttempts(defaults.getLockoutMaxFailedAttempts());
}
if (target.getMaxAge() == null && defaults.getMaxAge() != null) {
target.setMaxAge(defaults.getMaxAge());
}
if (target.getMinAge() == null && defaults.getMinAge() != null) {
target.setMinAge(defaults.getMinAge());
}
if (target.getPropagationUserControl() == null && defaults.getPropagationUserControl() != null) {
target.setPropagationUserControl(defaults.getPropagationUserControl());
}
if (target.getResetMethod() == null && defaults.getResetMethod() != null) {
target.setResetMethod(defaults.getResetMethod());
}
if (target.getStorageMethod() == null && defaults.getStorageMethod() != null) {
target.setStorageMethod(defaults.getStorageMethod());
}
if (target.getWarningBeforeExpirationDuration() == null && defaults.getWarningBeforeExpirationDuration() != null) {
target.setWarningBeforeExpirationDuration(defaults.getWarningBeforeExpirationDuration());
}
}
public static int getCredentialHistoryLength(CredentialPolicyType credentialPolicy) {
if (credentialPolicy == null) {
return 0;
}
Integer historyLength = credentialPolicy.getHistoryLength();
if (historyLength == null) {
return 0;
}
return historyLength;
}
public static CredentialsStorageTypeType getCredentialStoragetTypeType(CredentialsStorageMethodType storageMethod) {
if (storageMethod == null) {
return null;
}
return storageMethod.getStorageType();
}
/**
* Not very systematic. Used mostly in hacks.
* @param securityPolicy
* @return
*/
public static ValuePolicyType getPasswordPolicy(SecurityPolicyType securityPolicy) {
if (securityPolicy == null) {
return null;
}
CredentialsPolicyType creds = securityPolicy.getCredentials();
if (creds == null) {
return null;
}
PasswordCredentialsPolicyType passd = creds.getPassword();
if (passd == null) {
return null;
}
ObjectReferenceType valuePolicyRef = passd.getValuePolicyRef();
if (valuePolicyRef == null) {
return null;
}
PrismObject<ValuePolicyType> policyObj = valuePolicyRef.asReferenceValue().getObject();
if (policyObj == null) {
return null;
}
return policyObj.asObjectable();
}
}