Skip to content
This repository was archived by the owner on Sep 28, 2022. It is now read-only.
Merged
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 @@ -251,7 +251,7 @@
access="permitAll()"/>
<security:intercept-url pattern="#{T(cz.muni.ics.oidc.web.controllers.LoginController).MAPPING_FAILURE}"
access="permitAll()"/>
<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_EXCEPTION')"/>
<security:custom-filter ref="mdcFilter" before="FIRST"/>
<security:custom-filter ref="metadataGeneratorFilter" before="CHANNEL_FILTER"/>
<security:custom-filter ref="clearSessionFilter" after="CHANNEL_FILTER"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cz.muni.ics.oidc.saml;

import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;

public class ExtendedOAuth2Exception extends OAuth2Exception {

private final String errorCode;

public ExtendedOAuth2Exception(String errorCode, String msg) {
super(msg);
this.errorCode = errorCode;
}

@Override
public String getOAuth2ErrorCode() {
return errorCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import java.util.Collection;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.saml.SAMLAuthenticationProvider;
import org.springframework.security.saml.SAMLCredential;

Expand All @@ -27,6 +28,15 @@ public PerunSamlAuthenticationProvider(List<String> adminIds) {
}
}

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try {
return super.authenticate(authentication);
} catch (Exception e) {
return new SamlAuthenticationExceptionAuthenticationToken(e);
}
}

@Override
protected Object getPrincipal(SAMLCredential credential, Object userDetail) {
PerunUser user = (PerunUser) userDetail;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* Copyright 2009 Vladimir Schäfer
*
* 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
*
* https://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 cz.muni.ics.oidc.saml;

import java.security.Principal;
import java.util.Collections;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.opensaml.common.SAMLException;
import org.opensaml.saml2.core.StatusCode;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.saml.SAMLStatusException;

@Getter
@ToString
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class SamlAuthenticationExceptionAuthenticationToken extends AbstractAuthenticationToken {

private static final Principal PRINCIPAL = new SamlAuthenticationExceptionPrincipal();
public static final SimpleGrantedAuthority ROLE_EXCEPTION = new SimpleGrantedAuthority("ROLE_EXCEPTION");
private final Exception causeException;

public SamlAuthenticationExceptionAuthenticationToken(Exception causeException) {
super(Collections.singleton(ROLE_EXCEPTION));
this.causeException = causeException;
}

@Override
public Object getCredentials() {
return "EXCEPTION_IN_SAML_AUTHENTICATION";
}

@Override
public Object getPrincipal() {
return PRINCIPAL;
}

@Override
public boolean isAuthenticated() {
return true;
}

@Override
public void eraseCredentials() { }

public OAuth2Exception createOAuth2Exception() {
if (causeException != null) {
Throwable t = causeException;
while (t.getCause() != null) {
log.warn("OAuth2 exception from SAML translation: {} - {}", t.getClass().getSimpleName(), t.getMessage());
t = t.getCause();
}
if (t instanceof InsufficientAuthenticationException) {
return new ExtendedOAuth2Exception("unmet_authentication_requirements", t.getMessage());
}
if (t instanceof SAMLStatusException) {
String code = ((SAMLStatusException) t).getStatusCode();
if (StatusCode.NO_AUTHN_CONTEXT_URI.equalsIgnoreCase(code)) {
return new ExtendedOAuth2Exception("unmet_authentication_requirements", t.getMessage());
}
}
return new OAuth2Exception(t.getMessage());
}
//TODO: handle
return new OAuth2Exception("");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* Copyright 2009 Vladimir Schäfer
*
* 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
*
* https://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 cz.muni.ics.oidc.saml;

import java.security.Principal;
import java.util.Collections;
import javax.security.auth.Subject;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

public class SamlAuthenticationExceptionPrincipal implements Principal {

@Override
public String getName() {
return null;
}

@Override
public boolean implies(Subject subject) {
return Principal.super.implies(subject);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cz.muni.ics.oidc.server.filters;

import cz.muni.ics.oidc.exceptions.ConfigurationException;
import cz.muni.ics.oidc.saml.SamlAuthenticationExceptionAuthenticationToken;
import cz.muni.ics.oidc.saml.SamlProperties;
import java.io.IOException;
import java.util.Arrays;
Expand All @@ -13,6 +14,8 @@
import javax.servlet.http.HttpSession;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

/**
* Abstract class for Perun AuthProc filters. All filters defined and called in the
Expand Down Expand Up @@ -117,6 +120,10 @@ private boolean skip(HttpServletRequest req) {
}
log.debug("{} - marking filter as applied", filterName);
req.getSession(true).setAttribute(getSessionAppliedParamName(), true);
Authentication a = SecurityContextHolder.getContext().getAuthentication();
if (a instanceof SamlAuthenticationExceptionAuthenticationToken) {
return true;
}
String sub = FiltersUtils.getUserIdentifier(req, samlProperties.getUserIdentifierAttribute());
String clientId = FiltersUtils.getClientId(req);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ public static Map<String, String> createRequestMap(Map<String, String[]> paramet
* @param clientService service fetching client details
* @return extracted client, null if some error occurs
*/
@SuppressWarnings("unchecked")
public static ClientDetailsEntity extractClientFromRequest(HttpServletRequest request,
OAuth2RequestFactory authRequestFactory,
ClientDetailsEntityService clientService)
Expand Down Expand Up @@ -199,11 +198,15 @@ public static PerunUser getPerunUserById(PerunAdapter perunAdapter, SAMLCredenti
}

public static SAMLCredential getSamlCredential(HttpServletRequest request) {
ExpiringUsernameAuthenticationToken p = (ExpiringUsernameAuthenticationToken) request.getUserPrincipal();
if (p == null) {
if (request.getUserPrincipal() instanceof ExpiringUsernameAuthenticationToken) {
ExpiringUsernameAuthenticationToken p = (ExpiringUsernameAuthenticationToken) request.getUserPrincipal();
if (p == null) {
return null;
}
return (SAMLCredential) p.getCredentials();
} else {
return null;
}
return (SAMLCredential) p.getCredentials();
}

public static String getExtLogin(SAMLCredential credential, String idAttribute) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.web.WebHtmlClasses;
import cz.muni.ics.openid.connect.view.HttpCodeView;
import cz.muni.ics.openid.connect.view.JsonErrorView;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.opensaml.saml2.core.StatusCode;
import org.opensaml.ws.message.encoder.MessageEncodingException;
import org.opensaml.xml.util.XMLHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
Expand Down Expand Up @@ -62,7 +65,11 @@ public String loginFailure(HttpServletRequest req, Map<String, Object> model) {
if (exc != null) {
String code = exc.getStatusCode();
if (StatusCode.NO_AUTHN_CONTEXT_URI.equalsIgnoreCase(code)) {
model.put(KEY_ERROR_MSG, "login_failure.no_authn_context.msg");
model.put(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
model.put(JsonErrorView.ERROR, "unmet_authentication_requirements");
model.put(JsonErrorView.ERROR_MESSAGE, "Cannot log in. MFA has been requested and not performed");
return JsonErrorView.VIEWNAME;
//model.put(KEY_ERROR_MSG, "login_failure.no_authn_context.msg");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package cz.muni.ics.openid.connect.request;


import static cz.muni.ics.oidc.saml.SamlAuthenticationExceptionAuthenticationToken.ROLE_EXCEPTION;

import com.google.common.base.Strings;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
Expand All @@ -37,17 +39,23 @@
import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oauth2.model.PKCEAlgorithm;
import cz.muni.ics.oauth2.service.ClientDetailsEntityService;
import cz.muni.ics.oidc.saml.SamlAuthenticationExceptionAuthenticationToken;
import java.io.Serializable;
import java.text.ParseException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.stereotype.Component;

Expand Down Expand Up @@ -151,6 +159,28 @@ public AuthorizationRequest createAuthorizationRequest(Map<String, String> input
return request;
}

@Override
public OAuth2Request createOAuth2Request(AuthorizationRequest request) {
if (request.getAuthorities() != null && request.getAuthorities().contains(ROLE_EXCEPTION)) {
Authentication a = SecurityContextHolder.getContext().getAuthentication();
if (a instanceof SamlAuthenticationExceptionAuthenticationToken) {
throw ((SamlAuthenticationExceptionAuthenticationToken) a).createOAuth2Exception();
}
}
return super.createOAuth2Request(request);
}

@Override
public TokenRequest createTokenRequest(AuthorizationRequest authorizationRequest, String grantType) {
if (authorizationRequest.getAuthorities() != null && authorizationRequest.getAuthorities().contains(ROLE_EXCEPTION)) {
Authentication a = SecurityContextHolder.getContext().getAuthentication();
if (a instanceof SamlAuthenticationExceptionAuthenticationToken) {
throw ((SamlAuthenticationExceptionAuthenticationToken) a).createOAuth2Exception();
}
}
return super.createTokenRequest(authorizationRequest, grantType);
}

/**
*
* @param jwtString
Expand Down
Loading