Skip to content

Commit

Permalink
Adjusting secrurity to support pre-autheticated methods (MID-1816)
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Apr 15, 2014
1 parent 3cda0ae commit 1e26b46
Show file tree
Hide file tree
Showing 16 changed files with 171 additions and 203 deletions.
Expand Up @@ -431,8 +431,6 @@ private boolean skipProperty(PrismPropertyDefinition def) {
//user
names.add(UserType.F_RESULT);

names.add(CredentialsType.F_ALLOWED_IDM_ADMIN_GUI_ACCESS);

for (QName name : names) {
if (name.equals(def.getName())) {
return true;
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013 Evolveum
* Copyright (c) 2010-2014 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,11 +22,12 @@
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.security.api.UserProfileService;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_2a.*;

import com.evolveum.prism.xml.ns._public.types_2.ProtectedStringType;

import org.apache.commons.lang.StringUtils;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.http.WebRequest;
Expand All @@ -39,11 +40,11 @@
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;

import javax.servlet.http.HttpServletRequest;
import javax.xml.datatype.XMLGregorianCalendar;


import java.sql.Date;
import java.util.ArrayList;
import java.util.Calendar;
Expand All @@ -52,12 +53,13 @@

/**
* @author lazyman
* @author Radovan Semancik
*/
public class MidPointAuthenticationProvider implements AuthenticationProvider {

private static final Trace LOGGER = TraceManager.getTrace(MidPointAuthenticationProvider.class);
@Autowired(required = true)
private transient UserProfileService userManagerService;
private transient UserProfileService userProfileService;
@Autowired(required = true)
private transient Protector protector;
private int loginTimeout;
Expand All @@ -79,93 +81,77 @@ public void setMaxFailedLogins(int maxFailedLogins) {

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (StringUtils.isBlank((String) authentication.getPrincipal())
|| StringUtils.isBlank((String) authentication.getCredentials())) {
if (StringUtils.isBlank((String) authentication.getPrincipal())) {
throw new BadCredentialsException("web.security.provider.invalid");
}
// throw new BadCredentialsException("web.security.provider.illegal");
MidPointPrincipal user = null;
List<GrantedAuthority> grantedAuthorities = null;

MidPointPrincipal principal = null;
try {
user = userManagerService.getPrincipal((String) authentication.getPrincipal());
authenticateUser(user, (String) authentication.getCredentials());
} catch (BadCredentialsException ex) {
if (user != null && user.getUser() != null && user.getUser().getCredentials() != null) {
UserType userType = user.getUser();

CredentialsType credentials = userType.getCredentials();
PasswordType passwordType = credentials.getPassword();

int failedLogins = passwordType.getFailedLogins() != null ? passwordType.getFailedLogins() : 0;
passwordType.setFailedLogins(failedLogins++);
XMLGregorianCalendar systemTime = MiscUtil.asXMLGregorianCalendar(new Date(System
.currentTimeMillis()));
LoginEventType event = new LoginEventType();
event.setTimestamp(systemTime);
event.setFrom(getRemoteHost());
passwordType.setLastFailedLogin(event);
userManagerService.updateUser(user);
}

throw ex;
principal = userProfileService.getPrincipal((String) authentication.getPrincipal());
} catch (ObjectNotFoundException ex) {
LOGGER.debug("Authentication of user with username '{}' failed: not found: {}", ex.getMessage(), ex);
throw new BadCredentialsException("web.security.provider.access.denied");
} catch (Exception ex) {
LOGGER.error("Can't get user with username '{}'. Unknown error occured, reason {}.",
new Object[] { authentication.getPrincipal(), ex.getMessage() });
LOGGER.debug("Can't authenticate user '{}'.", new Object[] { authentication.getPrincipal() }, ex);
new Object[] { authentication.getPrincipal(), ex.getMessage(), ex });
throw new AuthenticationServiceException("web.security.provider.unavailable");
}

if (user != null) {
grantedAuthorities = new ArrayList<GrantedAuthority>();
UserType userType = user.getUser();
CredentialsType credentialsType = userType.getCredentials();

if (credentialsType == null) {
credentialsType = new CredentialsType();
userType.setCredentials(credentialsType);
}

boolean isAdminGuiAccess = credentialsType.isAllowedIdmAdminGuiAccess() != null ? credentialsType
.isAllowedIdmAdminGuiAccess() : false;
if (isAdminGuiAccess) {
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
} else {
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
}

/*
* List<Role> roles = new ArrayList<Role>(0);
* //user.getAssociatedRoles(); for (Role role : roles) {
* GrantedAuthority authority = new
* SimpleGrantedAuthority(role.getRoleName());
* grantedAuthorities.add(authority); }
*/
} else {
throw new BadCredentialsException("web.security.provider.invalid");

Authentication token = null;
try {
token = authenticateUser(principal, authentication);
} catch (BadCredentialsException ex) {
LOGGER.debug("Authentication of user with username '{}' failed: bad credentials: {}", ex.getMessage(), ex);
throw ex;
} catch (Exception ex) {
LOGGER.error("Can't authenticate user '{}': {}", new Object[] { authentication.getPrincipal() , ex.getMessage(), ex });
throw new AuthenticationServiceException("web.security.provider.unavailable");
}
return new UsernamePasswordAuthenticationToken(user, authentication.getCredentials(),
grantedAuthorities);

LOGGER.debug("User '{}' authenticated ({}), authorities: {}", new Object[]{authentication.getPrincipal(),
authentication.getClass().getSimpleName(), principal.getAuthorities()});
return token;
}

@Override
public boolean supports(Class<? extends Object> authentication) {
if (UsernamePasswordAuthenticationToken.class.equals(authentication)) {
return true;
}
if (PreAuthenticatedAuthenticationToken.class.equals(authentication)) {
return true;
}

return false;
}

private void authenticateUser(MidPointPrincipal user, String password) throws BadCredentialsException {
if (user == null || user.getUser() == null || user.getUser().getCredentials() == null) {
private Authentication authenticateUser(MidPointPrincipal principal, Authentication authentication) {
if (authentication instanceof UsernamePasswordAuthenticationToken) {
return authenticateUserPassword(principal, (String) authentication.getCredentials());
} else if (authentication instanceof PreAuthenticatedAuthenticationToken) {
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal, null,
principal.getAuthorities());
return token;
} else {
throw new AuthenticationServiceException("web.security.provider.unavailable");
}

}

private Authentication authenticateUserPassword(MidPointPrincipal principal, String password) throws BadCredentialsException {
if (StringUtils.isBlank(password)) {
throw new BadCredentialsException("web.security.provider.access.denied");
}

if (principal == null || principal.getUser() == null || principal.getUser().getCredentials() == null) {
throw new BadCredentialsException("web.security.provider.invalid");
}

if (!user.isEnabled()) {
if (!principal.isEnabled()) {
throw new BadCredentialsException("web.security.provider.disabled");
}

UserType userType = user.getUser();
UserType userType = principal.getUser();
CredentialsType credentials = userType.getCredentials();

PasswordType passwordType = credentials.getPassword();
Expand All @@ -190,7 +176,7 @@ private void authenticateUser(MidPointPrincipal user, String password) throws Ba
throw new BadCredentialsException("web.security.provider.password.encoding");
}

Collection<Authorization> authorizations = user.getAuthorities();
Collection<Authorization> authorizations = principal.getAuthorities();
if (authorizations == null || authorizations.isEmpty()){
throw new BadCredentialsException("web.security.provider.access.denied");
}
Expand All @@ -212,6 +198,7 @@ private void authenticateUser(MidPointPrincipal user, String password) throws Ba
decoded = protectedString.getClearValue();
}
if (password.equals(decoded)) {
// Good password
if (failedLogins > 0) {
passwordType.setFailedLogins(0);
}
Expand All @@ -224,14 +211,26 @@ private void authenticateUser(MidPointPrincipal user, String password) throws Ba
passwordType.setPreviousSuccessfulLogin(passwordType.getLastSuccessfulLogin());
passwordType.setLastSuccessfulLogin(event);

userManagerService.updateUser(user);
return;
userProfileService.updateUser(principal);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(principal,
password, principal.getAuthorities());
return token;
} else {
// Bad password
passwordType.setFailedLogins(failedLogins++);
XMLGregorianCalendar systemTime = MiscUtil.asXMLGregorianCalendar(new Date(System
.currentTimeMillis()));
LoginEventType event = new LoginEventType();
event.setTimestamp(systemTime);
event.setFrom(getRemoteHost());
passwordType.setLastFailedLogin(event);
userProfileService.updateUser(principal);

throw new BadCredentialsException("web.security.provider.invalid");
}
} catch (EncryptionException ex) {
throw new AuthenticationServiceException("web.security.provider.unavailable", ex);
}

throw new BadCredentialsException("web.security.provider.invalid");
}

public static String getRemoteHost() {
Expand Down
Expand Up @@ -424,14 +424,6 @@ public static String createUserIcon(PrismObject<UserType> object) {
UserType user = object.asObjectable();
CredentialsType credentials = user.getCredentials();

//if allowedIdmAdminGuiAccess is true, it's superuser
if (credentials != null) {
Boolean allowedAdmin = credentials.isAllowedIdmAdminGuiAccess();
if (allowedAdmin != null && allowedAdmin) {
return "silk-user_red";
}
}

//if user has superuser role assigned, it's superuser
for (AssignmentType assignment : user.getAssignment()) {
ObjectReferenceType targetRef = assignment.getTargetRef();
Expand Down
10 changes: 10 additions & 0 deletions gui/admin-gui/src/main/webapp/WEB-INF/ctx-web-security.xml
Expand Up @@ -55,7 +55,11 @@ http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
</session-management>

<!-- For SSO integration use the following: -->
<!-- <custom-filter position="PRE_AUTH_FILTER" ref="requestHeaderAuthenticationFilter" /> -->

<form-login login-page="/login" default-target-url="/home" />

</http>

<beans:bean id="accessDecisionManager" class="com.evolveum.midpoint.web.security.MidPointGuiAuthorizationEvaluator">
Expand All @@ -73,6 +77,12 @@ http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<beans:value type="java.lang.Integer">3</beans:value>
</beans:property>
</beans:bean>

<!-- Following bean is used with pre-authentication based on HTTP headers (e.g. for SSO integration) -->
<beans:bean id="requestHeaderAuthenticationFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<beans:property name="principalRequestHeader" value="SM_USER"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>

<authentication-manager alias="authenticationManager">
<authentication-provider ref="midPointAuthenticationProvider"/>
Expand Down
20 changes: 0 additions & 20 deletions infra/schema/src/main/resources/xml/ns/public/common/common-2a.xsd
Expand Up @@ -2429,26 +2429,6 @@
</xsd:element>
<!-- More credentail types may be here, such as OTP seeds, X.509 credentials,
etc. -->
<xsd:element name="allowedIdmAdminGuiAccess" type="xsd:boolean" minOccurs="0" default="false">
<xsd:annotation>
<xsd:documentation>
DEPRECATED. DO NO USE.
Use the authorization mechanism instead.
This option will be removed in the next version.

If true, the user will have access to the IDM ADMIN GUI. The
access will provide access to all functions, therefore
this is kind of "superuser" flag.

This is a temporary solution until we implement
fully-featured authorization mechanism.
</xsd:documentation>
<xsd:appinfo>
<a:displayName>Admin Gui Access</a:displayName>
<a:deprecated/>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:long" use="optional"/>
</xsd:complexType>
Expand Down
Expand Up @@ -97,31 +97,32 @@ public void testValueMultiShallow() throws Exception {
PrismAsserts.assertTripleNoMinus(outputTriple);
}

@Test
public void testValueBooleanTrue() throws Exception {
// WHEN
PrismValueDeltaSetTriple<PrismPropertyValue<String>> outputTriple = evaluator.evaluateMapping(
"mapping-value-boolean-true.xml",
"testValue",
new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_ALLOWED_IDM_ADMIN_GUI_ACCESS)); // target
// THEN
PrismAsserts.assertTripleZero(outputTriple, Boolean.TRUE);
PrismAsserts.assertTripleNoPlus(outputTriple);
PrismAsserts.assertTripleNoMinus(outputTriple);
}

@Test
public void testValueBooleanFalse() throws Exception {
// WHEN
PrismValueDeltaSetTriple<PrismPropertyValue<String>> outputTriple = evaluator.evaluateMapping(
"mapping-value-boolean-false.xml",
"testValue",
new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_ALLOWED_IDM_ADMIN_GUI_ACCESS)); // target
// THEN
PrismAsserts.assertTripleZero(outputTriple, Boolean.FALSE);
PrismAsserts.assertTripleNoPlus(outputTriple);
PrismAsserts.assertTripleNoMinus(outputTriple);
}
// We do not have boolean property in the use any more ... but this is covered quite well in dynamic tests
// @Test
// public void testValueBooleanTrue() throws Exception {
// // WHEN
// PrismValueDeltaSetTriple<PrismPropertyValue<String>> outputTriple = evaluator.evaluateMapping(
// "mapping-value-boolean-true.xml",
// "testValue",
// new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_ALLOWED_IDM_ADMIN_GUI_ACCESS)); // target
// // THEN
// PrismAsserts.assertTripleZero(outputTriple, Boolean.TRUE);
// PrismAsserts.assertTripleNoPlus(outputTriple);
// PrismAsserts.assertTripleNoMinus(outputTriple);
// }
//
// @Test
// public void testValueBooleanFalse() throws Exception {
// // WHEN
// PrismValueDeltaSetTriple<PrismPropertyValue<String>> outputTriple = evaluator.evaluateMapping(
// "mapping-value-boolean-false.xml",
// "testValue",
// new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_ALLOWED_IDM_ADMIN_GUI_ACCESS)); // target
// // THEN
// PrismAsserts.assertTripleZero(outputTriple, Boolean.FALSE);
// PrismAsserts.assertTripleNoPlus(outputTriple);
// PrismAsserts.assertTripleNoMinus(outputTriple);
// }

@Test
public void testPathNoSource() throws Exception {
Expand Down
Expand Up @@ -193,25 +193,8 @@ private PrismObject<UserType> migrateUser(PrismObject<UserType> orig) {

PrismObject<UserType> migrated = orig.clone();


UserType migratedUserType = migrated.asObjectable();

//Credentials
if (origUserType.getCredentials() != null && origUserType.getCredentials().isAllowedIdmAdminGuiAccess() != null && origUserType.getCredentials().isAllowedIdmAdminGuiAccess()){
AssignmentType superUserRole = new AssignmentType();
superUserRole.setTargetRef(ObjectTypeUtil.createObjectRef(SystemObjectsType.ROLE_SUPERUSER.value(), ObjectTypes.ROLE));
migratedUserType.getAssignment().add(superUserRole);

if (origUserType.getCredentials().getPassword() == null){
migratedUserType.setCredentials(null);
} else{
CredentialsType migratedCredentials = origUserType.getCredentials().clone();
migratedCredentials.setAllowedIdmAdminGuiAccess(null);

migratedUserType.setCredentials(migratedCredentials);
}
}

// Activation
ActivationType origActivation = origUserType.getActivation();
if ((origActivation == null || origActivation.isEnabled() == null) &&
Expand Down

0 comments on commit 1e26b46

Please sign in to comment.