Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change the message when identifying with X509 and the account is suspended #901

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

import it.infn.mw.iam.persistence.model.IamAccount;
import it.infn.mw.iam.persistence.model.IamX509Certificate;
import it.infn.mw.iam.persistence.repository.IamX509CertificateRepository;

public class IamX509PreauthenticationProcessingFilter
extends AbstractPreAuthenticatedProcessingFilter {

Expand All @@ -39,19 +43,24 @@ public class IamX509PreauthenticationProcessingFilter
public static final String X509_CREDENTIAL_SESSION_KEY = "IAM_X509_CRED";
public static final String X509_ERROR_KEY = "IAM_X509_AUTHN_ERROR";
public static final String X509_CAN_LOGIN_KEY = "IAM_X509_CAN_LOGIN";

public static final String X509_SUSPENDED_ACCOUNT_KEY = "IAM_X509_SUSPENDED_ACCOUNT";

public static final String X509_AUTHN_REQUESTED_PARAM = "x509ClientAuth";

private final X509AuthenticationCredentialExtractor credentialExtractor;

private final AuthenticationSuccessHandler successHandler;

private final IamX509CertificateRepository certificateRepo;

public IamX509PreauthenticationProcessingFilter(X509AuthenticationCredentialExtractor extractor,
AuthenticationManager authenticationManager, AuthenticationSuccessHandler successHandler) {
AuthenticationManager authenticationManager, AuthenticationSuccessHandler successHandler,
IamX509CertificateRepository certificateRepo) {
setCheckForPrincipalChanges(false);
setAuthenticationManager(authenticationManager);
this.credentialExtractor = extractor;
this.successHandler = successHandler;
this.certificateRepo = certificateRepo;
}

protected boolean x509AuthenticationRequested(HttpServletRequest request) {
Expand Down Expand Up @@ -104,6 +113,19 @@ protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
return null;
}

Optional<IamX509Certificate> cert = certificateRepo
.findBySubjectDnAndIssuerDn(credential.get().getSubject(), credential.get().getIssuer());

if (cert.isEmpty()) {
return null;
}

IamAccount account = cert.get().getAccount();

if (!account.isActive()) {
request.setAttribute(X509_SUSPENDED_ACCOUNT_KEY, Boolean.TRUE);
}

credential.ifPresent(this::logX509CredentialInfo);
return credential.get().getSubject();
}
Expand All @@ -119,17 +141,17 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR
Authentication authentication) {

request.setAttribute(X509_CAN_LOGIN_KEY, Boolean.TRUE);

if (x509AuthenticationRequested(request)) {

try {
super.successfulAuthentication(request, response, authentication);
successHandler.onAuthenticationSuccess(request, response, authentication);

} catch (IOException | ServletException e) {
throw new X509AuthenticationError(e);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import it.infn.mw.iam.core.IamLocalAuthenticationProvider;
import it.infn.mw.iam.persistence.repository.IamAccountRepository;
import it.infn.mw.iam.persistence.repository.IamTotpMfaRepository;
import it.infn.mw.iam.persistence.repository.IamX509CertificateRepository;
import it.infn.mw.iam.service.aup.AUPSignatureCheckService;

@SuppressWarnings("deprecation")
Expand Down Expand Up @@ -109,7 +110,10 @@ public static class UserLoginConfig extends WebSecurityConfigurerAdapter {

@Autowired
private IamAccountRepository accountRepo;


@Autowired
private IamX509CertificateRepository certRepo;

@Autowired
private IamTotpMfaRepository totpMfaRepository;

Expand Down Expand Up @@ -146,7 +150,7 @@ public IamX509AuthenticationProvider iamX509AuthenticationProvider() {

public IamX509PreauthenticationProcessingFilter iamX509Filter() {
return new IamX509PreauthenticationProcessingFilter(x509CredentialExtractor,
iamX509AuthenticationProvider(), successHandler());
iamX509AuthenticationProvider(), successHandler(), certRepo);
}

protected AuthenticationEntryPoint entryPoint() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,16 @@
<div id="x509-authn-info">
You have been successfully authenticated as<br>
<strong>${IAM_X509_CRED.subject}</strong>
<c:if test="${!IAM_X509_CAN_LOGIN}">
<c:if test="${!IAM_X509_CAN_LOGIN && !IAM_X509_SUSPENDED_ACCOUNT}">
<p>
This certificate is not linked to any account in this organization
</p>
</c:if>
<c:if test="${IAM_X509_SUSPENDED_ACCOUNT}">
<p>
This certificate is linked to a suspended account in this organization
</p>
</c:if>
</div>
</c:if>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static it.infn.mw.iam.authn.x509.IamX509PreauthenticationProcessingFilter.X509_AUTHN_REQUESTED_PARAM;
import static it.infn.mw.iam.authn.x509.IamX509PreauthenticationProcessingFilter.X509_CAN_LOGIN_KEY;
import static it.infn.mw.iam.authn.x509.IamX509PreauthenticationProcessingFilter.X509_CREDENTIAL_SESSION_KEY;
import static it.infn.mw.iam.authn.x509.IamX509PreauthenticationProcessingFilter.X509_SUSPENDED_ACCOUNT_KEY;
import static java.lang.Boolean.TRUE;
import static java.util.Collections.singletonList;
import static org.hamcrest.MatcherAssert.assertThat;
Expand Down Expand Up @@ -124,11 +125,36 @@ public void testX509AuthenticationSuccessButNotRequestedLeadsToLoginPage() throw
.orElseThrow(
() -> new AssertionError("Expected test user linked with subject " + TEST_0_SUBJECT));

// Check that last login time is updated when loggin in with X.509 credentials
// Check that last login time is updated when login in with X.509 credentials
assertThat(resolvedAccount.getLastLoginTime().toInstant(), greaterThan(now));

}

@Test
public void testX509AuthenticationWhenAccountIsSuspended() throws Exception {

IamAccount testAccount = iamAccountRepo.findByUsername("test")
.orElseThrow(() -> new AssertionError("Expected test user not found"));

linkTest0CertificateToAccount(testAccount);

testAccount.setActive(false);
iamAccountRepo.save(testAccount);

IamAccount resolvedAccount = iamAccountRepo.findByCertificate(TEST_0_CERT_STRING)
.orElseThrow(
() -> new AssertionError("Expected test user linked to cert " + TEST_0_CERT_STRING));

assertThat(resolvedAccount.getUsername(), equalTo("test"));

mvc.perform(get("/").headers(test0SSLHeadersVerificationSuccess()))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"))
.andExpect(request().sessionAttribute(X509_CREDENTIAL_SESSION_KEY, not(nullValue())))
.andExpect(request().attribute(X509_SUSPENDED_ACCOUNT_KEY, is(TRUE)));

}

@Test
public void testX509AuthenticationVerifyFailedLeadsToLoginPage() throws Exception {

Expand Down Expand Up @@ -195,7 +221,8 @@ public void testx509AccountLinking() throws Exception {
assertThat(linkedUser.isPresent(), is(true));
assertThat(linkedUser.get().getUsername(), is("test"));

Optional<IamX509Certificate> test0Cert = iamX509CertificateRepo.findBySubjectDnAndIssuerDn(TEST_0_SUBJECT, TEST_0_ISSUER);
Optional<IamX509Certificate> test0Cert =
iamX509CertificateRepo.findBySubjectDnAndIssuerDn(TEST_0_SUBJECT, TEST_0_ISSUER);
assertThat(test0Cert.isPresent(), is(true));

IamAccount linkedAccount = iamAccountRepo.findByCertificateSubject(TEST_0_SUBJECT)
Expand Down Expand Up @@ -234,11 +261,13 @@ public void testx509AccountLinking() throws Exception {
.andExpect(
flash().attribute(ACCOUNT_LINKING_DASHBOARD_MESSAGE_KEY, equalTo(confirmationMsg)));

Optional<IamX509Certificate> testCert1 = iamX509CertificateRepo.findBySubjectDnAndIssuerDn(TEST_0_SUBJECT, TEST_0_ISSUER);
Optional<IamX509Certificate> testCert1 =
iamX509CertificateRepo.findBySubjectDnAndIssuerDn(TEST_0_SUBJECT, TEST_0_ISSUER);
assertThat(testCert1.isPresent(), is(true));
assertThat(testCert1.get().getAccount().getUsername(), is("test"));

Optional<IamX509Certificate> testCert2 = iamX509CertificateRepo.findBySubjectDnAndIssuerDn(TEST_0_SUBJECT, TEST_NEW_ISSUER);

Optional<IamX509Certificate> testCert2 =
iamX509CertificateRepo.findBySubjectDnAndIssuerDn(TEST_0_SUBJECT, TEST_NEW_ISSUER);
assertThat(testCert2.isPresent(), is(true));
assertThat(testCert2.get().getAccount().getUsername(), is("test"));

Expand Down Expand Up @@ -424,8 +453,16 @@ public void testx509AuthNFailsIfDisabledUser() throws Exception {
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/login"));

mvc.perform(post("/login").param("username", "test").param("password", "password"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/login?error=failure"));

resolvedAccount.setActive(true);

mvc.perform(post("/login").param("username", "test").param("password", "password"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/dashboard"));

}

@Test
Expand Down
Loading