001package com.nimbusds.openid.connect.sdk.id;
002
003
004import java.io.IOException;
005import java.net.URI;
006import java.util.List;
007import java.util.Set;
008
009import com.nimbusds.jose.util.Resource;
010import com.nimbusds.jose.util.ResourceRetriever;
011import com.nimbusds.oauth2.sdk.GeneralException;
012import com.nimbusds.oauth2.sdk.util.JSONArrayUtils;
013
014
015/**
016 * Sector identifier URI validator.
017 *
018 * <p>Related specifications:
019 *
020 * <ul>
021 *     <li>OpenID Connect Core 1.0, section 8.1.
022 *     <li>OpenID Connect Dynamic Client Registration 1.0, section 5.
023 * </ul>
024 */
025public class SectorIDURIValidator {
026        
027
028        /**
029         * The URL resource retriever.
030         */
031        private final ResourceRetriever resourceRetriever;
032
033
034        /**
035         * Creates a new sector identifier URI validator.
036         *
037         * @param resourceRetriever The URL resource retriever to use. Must not
038         *                          be {@code null}.
039         */
040        public SectorIDURIValidator(final ResourceRetriever resourceRetriever) {
041                if (resourceRetriever == null) {
042                        throw new IllegalArgumentException("The resource retriever must not be null");
043                }
044                this.resourceRetriever = resourceRetriever;
045        }
046
047
048        /**
049         * Returns the URL resource retriever.
050         *
051         * @return The resource retriever.
052         */
053        public ResourceRetriever getResourceRetriever() {
054                return resourceRetriever;
055        }
056
057
058        /**
059         * Validates the specified sector identifier URI by ensuring it lists
060         * all specified redirection URIs.
061         *
062         *
063         * @param sectorURI    The sector identifier URI. Must not be
064         *                     {@code null}.
065         * @param redirectURIs The redirection URIs of the client. Must not be
066         *                     {@code null}.
067         *
068         * @throws GeneralException If validation failed.
069         */
070        public void validate(final URI sectorURI, final Set<URI> redirectURIs)
071                throws GeneralException {
072
073                Resource resource;
074
075                try {
076                        resource = resourceRetriever.retrieveResource(sectorURI.toURL());
077                } catch (IOException e) {
078                        throw new GeneralException("Couldn't retrieve the sector ID JSON document: " + e.getMessage(), e);
079                }
080
081                if (resource.getContentType() == null) {
082                        throw new GeneralException("Couldn't validate sector ID URI: Missing Content-Type");
083                }
084
085                if (! resource.getContentType().toLowerCase().startsWith("application/json")) {
086                        throw new GeneralException("Couldn't validate sector ID URI: Content-Type must be application/json, found " + resource.getContentType());
087                }
088
089                List<URI> uriList = JSONArrayUtils.toURIList(JSONArrayUtils.parse(resource.getContent()));
090
091                for (URI uri: redirectURIs) {
092
093                        if (! uriList.contains(uri)) {
094                                throw new GeneralException("Sector ID URI validation failed: Redirect URI " + uri + " is missing from published JSON array at sector ID URI " + sectorURI);
095                        }
096                }
097        }
098}