Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Apr 6, 2016
2 parents 9c9fc20 + a6e8023 commit 5759643
Show file tree
Hide file tree
Showing 22 changed files with 2,260 additions and 51 deletions.
Expand Up @@ -31,6 +31,7 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;

/**
* @author Vilo Repan
Expand Down Expand Up @@ -143,6 +144,7 @@ public abstract class SchemaConstants {
public static final ItemPath PATH_ATTRIBUTES = new ItemPath(C_ATTRIBUTES);
public static final ItemPath PATH_ASSOCIATION = new ItemPath(C_ASSOCIATION);
public static final ItemPath PATH_TRIGGER = new ItemPath(ObjectType.F_TRIGGER);
public static final ItemPath PATH_CREDENTIALS_PASSWORD_FAILED_LOGINS = new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_FAILED_LOGINS);

public static final String NS_PROVISIONING = NS_MIDPOINT_PUBLIC + "/provisioning";
public static final String NS_PROVISIONING_LIVE_SYNC = NS_PROVISIONING + "/liveSync-1.xsd";
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013 Evolveum
* Copyright (c) 2010-2016 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2015 Evolveum
* Copyright (c) 2010-2016 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -122,6 +122,10 @@ public Class<O> getObjectTypeClass() {
return objectTypeClass;
}

public boolean canRepresent(Class type) {
return type.isAssignableFrom(objectTypeClass);
}

public PrismContext getPrismContext() {
return lensContext.getPrismContext();
}
Expand Down
Expand Up @@ -64,12 +64,15 @@
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.IterationSpecificationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LockoutStatusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectPolicyConfigurationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateMappingEvaluationPhaseType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PropertyConstraintType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.TimeIntervalStatusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
Expand All @@ -87,6 +90,7 @@ public class FocusProcessor {
private static final Trace LOGGER = TraceManager.getTrace(FocusProcessor.class);

private PrismContainerDefinition<ActivationType> activationDefinition;
private PrismPropertyDefinition<Integer> failedLoginsDefinition;

@Autowired(required = true)
private InboundProcessor inboundProcessor;
Expand Down Expand Up @@ -438,6 +442,17 @@ private <F extends FocusType> void processActivation(LensContext<F> context, XML
return;
}

processActivationAdministrativeAndValidity(focusContext, now, result);

if (focusContext.canRepresent(UserType.class)) {
processActivationLockout((LensFocusContext<UserType>) focusContext, now, result);
}
}

private <F extends FocusType> void processActivationAdministrativeAndValidity(LensFocusContext<F> focusContext, XMLGregorianCalendar now,
OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException {

TimeIntervalStatusType validityStatusNew = null;
TimeIntervalStatusType validityStatusCurrent = null;
XMLGregorianCalendar validityChangeTimestamp = null;
Expand Down Expand Up @@ -497,6 +512,70 @@ private <F extends FocusType> void processActivation(LensContext<F> context, XML
LOGGER.trace("Effective status change {} -> {}", effectiveStatusCurrent, effectiveStatusNew);
recordEffectiveStatusDelta(focusContext, effectiveStatusNew, now);
}


}

private <F extends FocusType> void processActivationLockout(LensFocusContext<UserType> focusContext, XMLGregorianCalendar now,
OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException {

ActivationType activationNew = null;
ActivationType activationCurrent = null;

LockoutStatusType lockoutStatusNew = null;
LockoutStatusType lockoutStatusCurrent = null;

PrismObject<UserType> focusNew = focusContext.getObjectNew();
if (focusNew != null) {
activationNew = focusNew.asObjectable().getActivation();
if (activationNew != null) {
lockoutStatusNew = activationNew.getLockoutStatus();
}
}

PrismObject<UserType> focusCurrent = focusContext.getObjectCurrent();
if (focusCurrent != null) {
activationCurrent = focusCurrent.asObjectable().getActivation();
if (activationCurrent != null) {
lockoutStatusCurrent = activationCurrent.getLockoutStatus();
}
}

if (lockoutStatusNew == lockoutStatusCurrent) {
// No change, (almost) no work
LOGGER.trace("Skipping lockout processing because there was no change ({} -> {})", lockoutStatusCurrent, lockoutStatusNew);
return;
}

LOGGER.trace("Lockout change {} -> {}", lockoutStatusCurrent, lockoutStatusNew);

if (lockoutStatusNew == LockoutStatusType.NORMAL) {

CredentialsType credentialsTypeNew = focusNew.asObjectable().getCredentials();
if (credentialsTypeNew != null) {
PasswordType passwordTypeNew = credentialsTypeNew.getPassword();
if (passwordTypeNew != null) {
Integer failedLogins = passwordTypeNew.getFailedLogins();
if (failedLogins != null && failedLogins != 0) {
PrismPropertyDefinition<Integer> failedLoginsDef = getFailedLoginsDefinition();
PropertyDelta<Integer> failedLoginsDelta = failedLoginsDef.createEmptyDelta(SchemaConstants.PATH_CREDENTIALS_PASSWORD_FAILED_LOGINS);
failedLoginsDelta.setValueToReplace(new PrismPropertyValue<Integer>(0, OriginType.USER_POLICY, null));
focusContext.swallowToProjectionWaveSecondaryDelta(failedLoginsDelta);
}
}
}

if (activationNew != null && activationNew.getLockoutExpirationTimestamp() != null) {
PrismContainerDefinition<ActivationType> activationDefinition = getActivationDefinition();
PrismPropertyDefinition<XMLGregorianCalendar> lockoutExpirationTimestampDef = activationDefinition.findPropertyDefinition(ActivationType.F_LOCKOUT_EXPIRATION_TIMESTAMP);
PropertyDelta<XMLGregorianCalendar> lockoutExpirationTimestampDelta
= lockoutExpirationTimestampDef.createEmptyDelta(new ItemPath(UserType.F_ACTIVATION, ActivationType.F_LOCKOUT_EXPIRATION_TIMESTAMP));
lockoutExpirationTimestampDelta.setValueToReplace();
focusContext.swallowToProjectionWaveSecondaryDelta(lockoutExpirationTimestampDelta);
}
}

}

private <F extends ObjectType> void recordValidityDelta(LensFocusContext<F> focusContext, TimeIntervalStatusType validityStatusNew,
Expand Down Expand Up @@ -548,6 +627,14 @@ private PrismContainerDefinition<ActivationType> getActivationDefinition() {
return activationDefinition;
}

private PrismPropertyDefinition<Integer> getFailedLoginsDefinition() {
if (failedLoginsDefinition == null) {
PrismObjectDefinition<UserType> userDef = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(UserType.class);
failedLoginsDefinition = userDef.findPropertyDefinition(SchemaConstants.PATH_CREDENTIALS_PASSWORD_FAILED_LOGINS);
}
return failedLoginsDefinition;
}

/**
* Adds deltas for iteration and iterationToken to the focus if needed.
*/
Expand Down
Expand Up @@ -49,8 +49,10 @@
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractCredentialPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractCredentialType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LockoutStatusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LoginEventType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordCredentialsPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType;
Expand Down Expand Up @@ -80,8 +82,6 @@ public class AuthenticationEvaluatorImpl implements AuthenticationEvaluator {
@Autowired(required = true)
private SecurityHelper securityHelper;

// TODO: auditing - through securityHelper

@Override
public UsernamePasswordAuthenticationToken authenticateUserPassword(ConnectionEnvironment connEnv, String enteredUsername, String enteredPassword)
throws BadCredentialsException, AuthenticationCredentialsNotFoundException, DisabledException, LockedException,
Expand Down Expand Up @@ -309,6 +309,10 @@ private boolean isLockedOut(AbstractCredentialType credentialsType, AbstractCred

private boolean isOverFailedLockoutAttempts(AbstractCredentialType credentialsType, AbstractCredentialPolicyType credentialsPolicy) {
int failedLogins = credentialsType.getFailedLogins() != null ? credentialsType.getFailedLogins() : 0;
return isOverFailedLockoutAttempts(failedLogins, credentialsPolicy);
}

private boolean isOverFailedLockoutAttempts(int failedLogins, AbstractCredentialPolicyType credentialsPolicy) {
return credentialsPolicy != null && credentialsPolicy.getLockoutMaxFailedAttempts() != null &&
credentialsPolicy.getLockoutMaxFailedAttempts() > 0 && failedLogins >= credentialsPolicy.getLockoutMaxFailedAttempts();
}
Expand Down Expand Up @@ -342,6 +346,12 @@ private void recordPasswordAuthenticationSuccess(MidPointPrincipal principal, Co

passwordType.setPreviousSuccessfulLogin(passwordType.getLastSuccessfulLogin());
passwordType.setLastSuccessfulLogin(event);

ActivationType activation = principal.getUser().getActivation();
if (activation != null) {
activation.setLockoutStatus(LockoutStatusType.NORMAL);
activation.setLockoutExpirationTimestamp(null);
}

userProfileService.updateUser(principal);

Expand All @@ -355,32 +365,55 @@ private void recordAuthenticationSuccess(MidPointPrincipal principal, Connection
private void recordPasswordAuthenticationFailure(MidPointPrincipal principal, ConnectionEnvironment connEnv,
PasswordType passwordType, PasswordCredentialsPolicyType passwordCredentialsPolicy, String reason) {
Integer failedLogins = passwordType.getFailedLogins();
LoginEventType lastFailedLogin = passwordType.getLastFailedLogin();
XMLGregorianCalendar lastFailedLoginTs = null;
if (lastFailedLogin != null) {
lastFailedLoginTs = lastFailedLogin.getTimestamp();
}

if (passwordCredentialsPolicy != null) {
Duration lockoutFailedAttemptsDuration = passwordCredentialsPolicy.getLockoutFailedAttemptsDuration();
if (lockoutFailedAttemptsDuration != null) {
LoginEventType lastFailedLogin = passwordType.getLastFailedLogin();
if (lastFailedLogin != null) {
XMLGregorianCalendar lastFailedLoginTs = lastFailedLogin.getTimestamp();
if (lastFailedLoginTs != null) {
XMLGregorianCalendar failedLoginsExpirationTs = XmlTypeConverter.addDuration(lastFailedLoginTs, lockoutFailedAttemptsDuration);
if (clock.isPast(failedLoginsExpirationTs)) {
failedLogins = 0;
}
if (lastFailedLoginTs != null) {
XMLGregorianCalendar failedLoginsExpirationTs = XmlTypeConverter.addDuration(lastFailedLoginTs, lockoutFailedAttemptsDuration);
if (clock.isPast(failedLoginsExpirationTs)) {
failedLogins = 0;
}
}
}
}
if (failedLogins == null) {
passwordType.setFailedLogins(1);
failedLogins = 1;
} else {
passwordType.setFailedLogins(failedLogins + 1);
failedLogins++;
}

passwordType.setFailedLogins(failedLogins);

LoginEventType event = new LoginEventType();
event.setTimestamp(clock.currentTimeXMLGregorianCalendar());
event.setFrom(connEnv.getRemoteHost());

passwordType.setLastFailedLogin(event);

ActivationType activationType = principal.getUser().getActivation();

if (failedLogins != null && isOverFailedLockoutAttempts(failedLogins, passwordCredentialsPolicy)) {
if (activationType == null) {
activationType = new ActivationType();
principal.getUser().setActivation(activationType);
}
activationType.setLockoutStatus(LockoutStatusType.LOCKED);
XMLGregorianCalendar lockoutExpirationTs = null;
if (passwordCredentialsPolicy != null) {
Duration lockoutDuration = passwordCredentialsPolicy.getLockoutDuration();
if (lockoutDuration != null) {
lockoutExpirationTs = XmlTypeConverter.addDuration(event.getTimestamp(), lockoutDuration);
}
}
activationType.setLockoutExpirationTimestamp(lockoutExpirationTs);
}

userProfileService.updateUser(principal);

recordAuthenticationFailure(principal, connEnv, reason);
Expand Down
Expand Up @@ -266,6 +266,9 @@ private MidPointPrincipal save(MidPointPrincipal person, OperationResult result)
PrismObject<UserType> newUser = person.getUser().asPrismObject();

ObjectDelta<UserType> delta = oldUser.diff(newUser);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Updating user {} with delta:\n{}", newUser, delta.debugDump());
}
repositoryService.modifyObject(UserType.class, delta.getOid(), delta.getModifications(),
new OperationResult(OPERATION_UPDATE_USER));

Expand Down

0 comments on commit 5759643

Please sign in to comment.