11/**
22 * SPDX-FileCopyrightText: 2018-2023 SAP SE or an SAP affiliate company and Cloud Security Client Java contributors
3- *<p>
3+ * <p>
44 * SPDX-License-Identifier: Apache-2.0
55 */
66package com .sap .cloud .security .token .validation .validators ;
77
8- import static com .sap .cloud .security .token .validation .ValidationResults .createInvalid ;
9- import static com .sap .cloud .security .token .validation .ValidationResults .createValid ;
10- import static com .sap .cloud .security .xsuaa .Assertions .assertNotEmpty ;
11-
12- import java .net .URI ;
13- import java .net .URISyntaxException ;
14- import java .util .List ;
15-
16- import com .sap .cloud .security .config .Service ;
17- import org .slf4j .Logger ;
18- import org .slf4j .LoggerFactory ;
19-
208import com .sap .cloud .security .config .OAuth2ServiceConfiguration ;
9+ import com .sap .cloud .security .json .JsonParsingException ;
2110import com .sap .cloud .security .token .Token ;
2211import com .sap .cloud .security .token .validation .ValidationResult ;
2312import com .sap .cloud .security .token .validation .Validator ;
13+ import org .slf4j .Logger ;
14+ import org .slf4j .LoggerFactory ;
15+
16+ import java .net .MalformedURLException ;
17+ import java .net .URL ;
18+ import java .util .List ;
19+ import java .util .Objects ;
20+ import java .util .regex .Pattern ;
21+
22+ import static com .sap .cloud .security .token .validation .ValidationResults .createInvalid ;
23+ import static com .sap .cloud .security .token .validation .ValidationResults .createValid ;
24+ import static com .sap .cloud .security .xsuaa .Assertions .assertNotEmpty ;
2425
2526/**
2627 * Validates that the jwt token is issued by a trust worthy identity provider.
3738 * These checks are a prerequisite for using the `JwtSignatureValidator`.
3839 */
3940class JwtIssuerValidator implements Validator <Token > {
41+ protected static final String HTTPS_SCHEME = "https://" ;
4042 private final List <String > domains ;
4143 protected final Logger logger = LoggerFactory .getLogger (getClass ());
4244
@@ -55,55 +57,34 @@ class JwtIssuerValidator implements Validator<Token> {
5557
5658 @ Override
5759 public ValidationResult validate (Token token ) {
58- String issuer = token .getIssuer ();
59- if (token .getService ().equals (Service .IAS ) && !issuer .startsWith ("http" )) {
60- issuer = "https://" + issuer ;
61- }
62- ValidationResult validationResult = validateUrl (issuer );
63- if (validationResult .isErroneous ()) {
64- return validationResult ;
60+ String issuer ;
61+
62+ try {
63+ issuer = token .getIssuer ();
64+ } catch (JsonParsingException e ) {
65+ return createInvalid ("Issuer validation can not be performed because token issuer claim was not a String value." );
6566 }
66- return matchesTokenIssuerUrl (issuer );
67- }
6867
69- private ValidationResult matchesTokenIssuerUrl (String issuer ) {
70- URI issuerUri = URI .create (issuer );
71- if (issuerUri .getQuery () == null && issuerUri .getFragment () == null && issuerUri .getHost () != null ) {
72- for (String d : domains ) {
73- if (issuerUri .getHost ().endsWith (d )) {
74- return createValid ();
75- }
76- }
68+ if (issuer == null || issuer .trim ().isEmpty ()) {
69+ return createInvalid ("Issuer validation can not be performed because token does not contain an issuer claim." );
7770 }
78- return createInvalid (
79- "Issuer is not trusted because issuer '{}' doesn't match any of these domains '{}' of the identity provider." ,
80- issuer , domains );
81- }
8271
83- private ValidationResult validateUrl (String issuer ) {
84- URI issuerUri ;
72+ String issuerUrl = issuer .startsWith (HTTPS_SCHEME ) ? issuer : HTTPS_SCHEME + issuer ;
8573 try {
86- if (issuer == null || issuer .trim ().isEmpty ()) {
87- return createInvalid (
88- "Issuer validation can not be performed because Jwt token does not contain an issuer claim." );
89- }
90- if (!issuer .startsWith ("http" )) {
91- return createInvalid (
92- "Issuer is not trusted because issuer '{}' does not provide a valid URI (missing http scheme). Please contact your Identity Provider Administrator." ,
93- issuer );
94- }
95- issuerUri = new URI (issuer );
96- if (issuerUri .getQuery () == null && issuerUri .getFragment () == null && issuerUri .getHost () != null ) {
74+ new URL (issuerUrl );
75+ } catch (MalformedURLException e ) {
76+ return createInvalid ("Issuer validation can not be performed because token issuer is not a valid URL suitable for https." );
77+ }
78+
79+ String issuerDomain = issuerUrl .substring (HTTPS_SCHEME .length ());
80+ for (String d : domains ) {
81+ // a string that ends with .<trustedDomain> and contains 1-63 letters, digits or '-' before that for the subdomain
82+ String validSubdomainPattern = String .format ("^[a-zA-Z0-9-]{1,63}\\ .%s$" , Pattern .quote (d ));
83+ if (Objects .equals (d , issuerDomain ) || issuerDomain .matches (validSubdomainPattern )) {
9784 return createValid ();
9885 }
99- } catch (URISyntaxException e ) {
100- logger .error (
101- "Error: issuer claim '{}' does not provide a valid URI: {}. Please contact your Identity Provider Administrator." ,
102- issuer , e .getMessage (), e );
10386 }
104- return createInvalid (
105- "Issuer is not trusted because issuer does not provide a valid URI. Please contact your Identity Provider Administrator." ,
106- issuer );
107- }
10887
88+ return createInvalid ("Issuer {} was not a trusted domain or a subdomain of the trusted domains {}." , issuer , domains );
89+ }
10990}
0 commit comments