001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.openid.connect.sdk.id; 019 020 021import com.nimbusds.jose.util.Resource; 022import com.nimbusds.jose.util.ResourceRetriever; 023import com.nimbusds.oauth2.sdk.GeneralException; 024import com.nimbusds.oauth2.sdk.ciba.BackChannelTokenDeliveryMode; 025import com.nimbusds.oauth2.sdk.util.JSONArrayUtils; 026import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata; 027 028import java.io.IOException; 029import java.net.URI; 030import java.util.*; 031 032 033/** 034 * Sector identifier URI validator. 035 * 036 * <p>Related specifications: 037 * 038 * <ul> 039 * <li>OpenID Connect Core 1.0 040 * <li>OpenID Connect Dynamic Client Registration 1.0 041 * <li>OpenID Connect CIBA Flow - Core 1.0 042 * </ul> 043 */ 044public class SectorIDURIValidator { 045 046 047 /** 048 * The URL resource retriever. 049 */ 050 private final ResourceRetriever resourceRetriever; 051 052 053 /** 054 * Creates a new sector ID URI validator. 055 * 056 * @param resourceRetriever The URL resource retriever to use. Must not 057 * be {@code null}. 058 */ 059 public SectorIDURIValidator(final ResourceRetriever resourceRetriever) { 060 this.resourceRetriever = Objects.requireNonNull(resourceRetriever); 061 } 062 063 064 /** 065 * Returns the URL resource retriever. 066 * 067 * @return The resource retriever. 068 */ 069 public ResourceRetriever getResourceRetriever() { 070 return resourceRetriever; 071 } 072 073 074 /** 075 * Validates the specified URIs for being present in a sector ID 076 * document. 077 * 078 * @param sectorURI The sector ID URI. Must not be {@code null}. 079 * @param urisToValidate The client URIs to check for being present in 080 * the sector ID JSON document. Must not be 081 * {@code null}. 082 * 083 * @throws GeneralException If validation failed. 084 */ 085 public void validate(final URI sectorURI, final Set<URI> urisToValidate) 086 throws GeneralException { 087 088 Resource resource; 089 try { 090 resource = resourceRetriever.retrieveResource(sectorURI.toURL()); 091 } catch (IOException e) { 092 throw new GeneralException("Couldn't retrieve the sector ID JSON document: " + e.getMessage(), e); 093 } 094 095 if (resource.getContentType() == null) { 096 throw new GeneralException("Couldn't validate sector ID: Missing HTTP Content-Type"); 097 } 098 099 if (! resource.getContentType().toLowerCase().startsWith("application/json")) { 100 throw new GeneralException("Couldn't validate sector ID: HTTP Content-Type must be application/json, found " + resource.getContentType()); 101 } 102 103 List<URI> uriList = JSONArrayUtils.toURIList(JSONArrayUtils.parse(resource.getContent())); 104 105 for (URI uri: urisToValidate) { 106 107 if (! uriList.contains(uri)) { 108 throw new GeneralException("Sector ID validation failed: URI " + uri + " not present at sector ID URI " + sectorURI); 109 } 110 } 111 } 112 113 114 /** 115 * Collects the client URIs for sector ID validation. 116 * 117 * <p>For the OAuth 2.0 authorisation code and implicit grants: 118 * {@code redirect_uris}. 119 * 120 * <p>For the OAuth 2.0 CIBA grant: {@code jwks_uri} for the poll and 121 * ping token delivery modes, 122 * {@code backchannel_client_notification_endpoint} for the push mode. 123 * 124 * @param clientMetadata The client metadata. Must not be {@code null}. 125 * 126 * @return The URIs for sector ID validation, empty set if none. 127 */ 128 public static Set<URI> collectURIsForValidation(final OIDCClientMetadata clientMetadata) { 129 130 Set<URI> uris = new HashSet<>(); 131 132 // Grant types code, implicit 133 if (clientMetadata.getRedirectionURIs() != null) { 134 uris.addAll(clientMetadata.getRedirectionURIs()); 135 } 136 137 // Grant type CIBA 138 if (BackChannelTokenDeliveryMode.POLL.equals(clientMetadata.getBackChannelTokenDeliveryMode()) || 139 BackChannelTokenDeliveryMode.PING.equals(clientMetadata.getBackChannelTokenDeliveryMode())) { 140 141 if (clientMetadata.getJWKSetURI() != null) { 142 uris.add(clientMetadata.getJWKSetURI()); 143 } 144 } 145 if (BackChannelTokenDeliveryMode.PUSH.equals(clientMetadata.getBackChannelTokenDeliveryMode())) { 146 147 if (clientMetadata.getBackChannelClientNotificationEndpoint() != null) { 148 uris.add(clientMetadata.getBackChannelClientNotificationEndpoint()); 149 } 150 } 151 152 return Collections.unmodifiableSet(uris); 153 } 154}