Skip to content
This repository was archived by the owner on Sep 28, 2022. It is now read-only.

Commit ff184f1

Browse files
author
Dominik František Bučík
committed
feat: 🎸 Return samlError from token in devicecode
BREAKING CHANGE: requires DB update
1 parent e605eaa commit ff184f1

File tree

18 files changed

+342
-137
lines changed

18 files changed

+342
-137
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE device_code ADD recorded_error TEXT DEFAULT NULL;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE device_code ADD COLUMN recorded_error TEXT DEFAULT NULL;

perun-oidc-server-webapp/src/main/resources/localization/messages_cs.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,7 @@ login_success_msg=Byl(a) jste \u00FAsp\u011B\u0161n\u011B p\u0159ihl\u00E1\u0161
184184
logout_denied_title=Odhl\u00E1\u0161en\u00ED zru\u0161eno
185185
logout_denied_header=Odhl\u00E1\u0161en\u00ED zru\u0161eno
186186
logout_denied_msg=Proces odhl\u00E1\u0161en\u00ED byl zastaven.
187+
188+
# Device flow error
189+
device_flow_error_header=Do\u0161lo ke chyb\u011B
190+
device_flow_error_message=P\u0159i schv\u00E1len\u00ED p\u0159\u00EDstupu aplikace/za\u0159\u00EDzen\u00ED k informac\u00EDm pod Va\u0161\u00ED identitou do\u0161lo ke chyb\u011B. Pro v\u00EDce informac\u00ED se vra\u0165te do aplikace, kter\u00E1 tento proces iniciovala.

perun-oidc-server-webapp/src/main/resources/localization/messages_en.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,6 @@ logout_denied_title=Logout denied
184184
logout_denied_header=Logout canceled
185185
logout_denied_msg=You have canceled the logout process.
186186

187+
# Device flow error
188+
device_flow_error_header=Ooops, there was an error
189+
device_flow_error_message=There was an error in the approval process. To see the details, please get back to the application which has initiated your login.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %>
2+
<%@ page import="java.util.ArrayList" %>
3+
<%@ page import="java.util.List" %>
4+
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
5+
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
6+
<%@ taglib prefix="t" tagdir="/WEB-INF/tags/common" %>
7+
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
8+
9+
<%
10+
11+
List<String> cssLinks = new ArrayList<>();
12+
13+
pageContext.setAttribute("cssLinks", cssLinks);
14+
15+
%>
16+
17+
<spring:message code="device_flow_error_header" var="title"/>
18+
<t:header title="${title}" reqURL="${reqURL}" baseURL="${baseURL}" cssLinks="${cssLinks}" theme="${theme}"/>
19+
20+
<h1><spring:message code="device_flow_error_header"/></h1>
21+
22+
</div> <%-- header --%>
23+
24+
<div id="content">
25+
<p><spring:message code="device_flow_error_message"/></p>
26+
</div>
27+
</div><!-- wrap -->
28+
29+
<t:footer baseURL="${baseURL}" theme="${theme}"/>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
2+
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
3+
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
4+
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
5+
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
6+
<%@ taglib prefix="ls" tagdir="/WEB-INF/tags/lsaai" %>
7+
8+
<ls:header />
9+
10+
<h3><spring:message code="device_flow_error_header"/></h3>
11+
<p><spring:message code="device_flow_error_message"/></p>
12+
13+
<ls:footer/>

perun-oidc-server/src/main/java/cz/muni/ics/oauth2/model/DeviceCode.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@
2323
import static cz.muni.ics.oauth2.model.DeviceCode.QUERY_BY_USER_CODE;
2424
import static cz.muni.ics.oauth2.model.DeviceCode.QUERY_EXPIRED_BY_DATE;
2525

26+
import cz.muni.ics.oauth2.model.convert.ExtendedOAuth2ExceptionConverter;
27+
import cz.muni.ics.oidc.saml.ExtendedOAuth2Exception;
2628
import java.util.Date;
2729
import java.util.Map;
2830
import java.util.Set;
2931
import javax.persistence.CollectionTable;
3032
import javax.persistence.Column;
33+
import javax.persistence.Convert;
3134
import javax.persistence.ElementCollection;
3235
import javax.persistence.Entity;
3336
import javax.persistence.FetchType;
@@ -121,6 +124,10 @@ public class DeviceCode {
121124
@JoinColumn(name = "auth_holder_id")
122125
private AuthenticationHolderEntity authenticationHolder;
123126

127+
@Column(name = "recorded_error")
128+
@Convert(converter = ExtendedOAuth2ExceptionConverter.class)
129+
private ExtendedOAuth2Exception error;
130+
124131
public DeviceCode(String deviceCode,
125132
String userCode,
126133
Set<String> scope,
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*******************************************************************************
2+
* Copyright 2018 The MIT Internet Trust Consortium
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*******************************************************************************/
16+
17+
package cz.muni.ics.oauth2.model.convert;
18+
19+
import cz.muni.ics.oidc.saml.ExtendedOAuth2Exception;
20+
import javax.persistence.AttributeConverter;
21+
import javax.persistence.Converter;
22+
import lombok.extern.slf4j.Slf4j;
23+
24+
/**
25+
* Translates a Serializable object of certain primitive types
26+
* into a String for storage in the database, for use with the
27+
* OAuth2Request extensions map.
28+
*
29+
* This class does allow some extension data to be lost.
30+
*
31+
* @author jricher
32+
*/
33+
@Converter
34+
@Slf4j
35+
public class ExtendedOAuth2ExceptionConverter implements AttributeConverter<ExtendedOAuth2Exception, String> {
36+
37+
@Override
38+
public String convertToDatabaseColumn(ExtendedOAuth2Exception attribute) {
39+
return ExtendedOAuth2Exception.serialize(attribute);
40+
}
41+
42+
@Override
43+
public ExtendedOAuth2Exception convertToEntityAttribute(String dbData) {
44+
return ExtendedOAuth2Exception.deserialize(dbData);
45+
}
46+
47+
}

perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/DeviceCodeService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import cz.muni.ics.oauth2.exception.DeviceCodeCreationException;
2020
import cz.muni.ics.oauth2.model.ClientDetailsEntity;
2121
import cz.muni.ics.oauth2.model.DeviceCode;
22+
import cz.muni.ics.oidc.saml.ExtendedOAuth2Exception;
23+
import cz.muni.ics.oidc.saml.SamlAuthenticationExceptionAuthenticationToken;
2224
import java.util.Map;
2325
import java.util.Set;
2426
import org.springframework.security.oauth2.provider.ClientDetails;
@@ -40,4 +42,6 @@ public interface DeviceCodeService {
4042
DeviceCode createNewDeviceCode(Set<String> requestedScopes, ClientDetailsEntity client, Map<String, String> parameters) throws DeviceCodeCreationException;
4143

4244
void clearExpiredDeviceCodes();
45+
46+
void addErrorToCode(String userCode, ExtendedOAuth2Exception exc);
4347
}

perun-oidc-server/src/main/java/cz/muni/ics/oauth2/service/impl/DefaultDeviceCodeService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@
1616

1717
package cz.muni.ics.oauth2.service.impl;
1818

19+
import com.fasterxml.jackson.core.JsonProcessingException;
20+
import com.fasterxml.jackson.databind.ObjectMapper;
1921
import cz.muni.ics.data.AbstractPageOperationTemplate;
2022
import cz.muni.ics.oauth2.model.AuthenticationHolderEntity;
2123
import cz.muni.ics.oauth2.model.ClientDetailsEntity;
2224
import cz.muni.ics.oauth2.model.DeviceCode;
2325
import cz.muni.ics.oauth2.repository.impl.DeviceCodeRepository;
2426
import cz.muni.ics.oauth2.service.DeviceCodeService;
27+
import cz.muni.ics.oidc.saml.ExtendedOAuth2Exception;
28+
import cz.muni.ics.oidc.saml.SamlAuthenticationExceptionAuthenticationToken;
2529
import java.util.Collection;
2630
import java.util.Date;
2731
import java.util.Map;
@@ -153,4 +157,10 @@ public void clearDeviceCode(String deviceCode, ClientDetails client) {
153157

154158
}
155159

160+
@Override
161+
public void addErrorToCode(String userCode, ExtendedOAuth2Exception exc) {
162+
DeviceCode deviceCode = lookUpByUserCode(userCode);
163+
deviceCode.setError(exc);
164+
repository.save(deviceCode);
165+
}
156166
}

perun-oidc-server/src/main/java/cz/muni/ics/oauth2/token/DeviceTokenGranter.java

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
3434
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
3535
import org.springframework.stereotype.Component;
36+
import org.springframework.util.StringUtils;
3637

3738
/**
3839
* Implements https://tools.ietf.org/html/draft-ietf-oauth-device-flow
@@ -66,43 +67,29 @@ protected DeviceTokenGranter(AuthorizationServerTokenServices tokenServices, Cli
6667
*/
6768
@Override
6869
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
69-
7070
String deviceCode = tokenRequest.getRequestParameters().get("device_code");
71-
7271
// look up the device code and consume it
7372
DeviceCode dc = deviceCodeService.findDeviceCode(deviceCode, client);
74-
7573
if (dc != null) {
76-
7774
// make sure the code hasn't expired yet
7875
if (dc.getExpiration() != null && dc.getExpiration().before(new Date())) {
79-
8076
deviceCodeService.clearDeviceCode(deviceCode, client);
81-
8277
throw new DeviceCodeExpiredException("Device code has expired " + deviceCode);
83-
78+
} else if (dc.getError() != null) {
79+
throw dc.getError();
8480
} else if (!dc.isApproved()) {
85-
8681
// still waiting for approval
8782
throw new AuthorizationPendingException("Authorization pending for code " + deviceCode);
88-
8983
} else {
9084
// inherit the (approved) scopes from the original request
9185
tokenRequest.setScope(dc.getScope());
92-
9386
OAuth2Authentication auth = new OAuth2Authentication(getRequestFactory().createOAuth2Request(client, tokenRequest), dc.getAuthenticationHolder().getUserAuth());
94-
9587
deviceCodeService.clearDeviceCode(deviceCode, client);
96-
9788
return auth;
9889
}
9990
} else {
10091
throw new InvalidGrantException("Invalid device code: " + deviceCode);
10192
}
102-
10393
}
10494

105-
106-
107-
10895
}

perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/AuthenticationUtilities.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,17 @@
1717
package cz.muni.ics.oauth2.web;
1818

1919
import com.google.common.collect.ImmutableSet;
20+
import cz.muni.ics.oauth2.model.ClientDetailsEntity;
21+
import cz.muni.ics.oidc.models.Facility;
22+
import cz.muni.ics.oidc.models.PerunAttributeValue;
23+
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
24+
import java.util.Locale;
25+
import java.util.Set;
2026
import org.springframework.security.core.Authentication;
2127
import org.springframework.security.core.GrantedAuthority;
2228
import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
2329
import org.springframework.security.oauth2.provider.OAuth2Authentication;
30+
import org.springframework.util.StringUtils;
2431

2532
/**
2633
*
@@ -31,6 +38,9 @@
3138
*/
3239
public abstract class AuthenticationUtilities {
3340

41+
public static final Set<String> EU_EAA = Set.of("AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE",
42+
"EL", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL", "PT", "RO", "SK", "SI", "ES", "SE", "NO", "IS", "LI", "GB");
43+
3444
/**
3545
* Makes sure the authentication contains the given scope, throws an exception otherwise
3646
* @param auth the authentication object to check
@@ -73,4 +83,36 @@ public static boolean hasRole(Authentication auth, String role) {
7383

7484
}
7585

86+
public static String getJurisdiction(ClientDetailsEntity client) {
87+
if (!StringUtils.hasText(client.getJurisdiction()) || EU_EAA.contains(client.getJurisdiction())) {
88+
return "";
89+
} else if (client.getJurisdiction().length() > 2) {
90+
if ("EMBL".equalsIgnoreCase(client.getJurisdiction())) {
91+
return "EMBL";
92+
}
93+
return "INT";
94+
}
95+
96+
Locale l = new Locale("", client.getJurisdiction());
97+
return l.getDisplayCountry() + " (" + l.getISO3Country() + ")";
98+
}
99+
100+
public static boolean isTestSp(ClientDetailsEntity client, PerunAdapter perunAdapter, String testSpAttrName) {
101+
if (client == null || !StringUtils.hasText(client.getClientId())) {
102+
return true;
103+
}
104+
Facility facility = perunAdapter.getFacilityByClientId(client.getClientId());
105+
if (facility == null || facility.getId() == null) {
106+
return true;
107+
}
108+
109+
PerunAttributeValue attrValue = perunAdapter.getFacilityAttributeValue(facility.getId(), testSpAttrName);
110+
if (attrValue == null) {
111+
return false;
112+
} else if (attrValue.valueAsBoolean()) {
113+
return attrValue.valueAsBoolean();
114+
}
115+
return false;
116+
}
117+
76118
}

0 commit comments

Comments
 (0)