001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2022, Connect2id Ltd. 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.jose.jwk.source; 019 020 021import java.io.IOException; 022import java.net.URL; 023import java.util.Objects; 024 025import net.jcip.annotations.ThreadSafe; 026 027import com.nimbusds.jose.KeySourceException; 028import com.nimbusds.jose.jwk.JWKSet; 029import com.nimbusds.jose.proc.SecurityContext; 030import com.nimbusds.jose.util.Resource; 031import com.nimbusds.jose.util.ResourceRetriever; 032 033 034/** 035 * JWK set source that loads the keys from a {@link URL}, without health status 036 * reporting. 037 * 038 * @author Thomas Rørvik Skjølberg 039 * @author Vladimir Dzhuvinov 040 * @version 2022-11-22 041 */ 042@ThreadSafe 043public class URLBasedJWKSetSource<C extends SecurityContext> implements JWKSetSource<C> { 044 045 private final URL url; 046 private final ResourceRetriever resourceRetriever; 047 048 049 /** 050 * Creates a new URL based JWK set source. 051 * 052 * @param url The JWK set URL. Must not be {@code null}. 053 * @param resourceRetriever The resource retriever to use. Must not 054 * be {@code null}. 055 */ 056 public URLBasedJWKSetSource(final URL url, final ResourceRetriever resourceRetriever) { 057 Objects.requireNonNull(url, "The URL must not be null"); 058 this.url = url; 059 Objects.requireNonNull(resourceRetriever, "The resource retriever must not be null"); 060 this.resourceRetriever = resourceRetriever; 061 } 062 063 064 @Override 065 public JWKSet getJWKSet(final JWKSetCacheRefreshEvaluator refreshEvaluator, final long currentTime, final C context) throws KeySourceException { 066 067 Resource resource; 068 try { 069 resource = resourceRetriever.retrieveResource(url); 070 } catch (IOException e) { 071 throw new JWKSetRetrievalException("Couldn't retrieve JWK set from URL: " + e.getMessage(), e); 072 } 073 074 try { 075 // Note on error handling: We want to avoid any generic HTML document 076 // (i.e. default HTTP error pages) and other invalid responses being accepted 077 // as an empty list of JWKs. This is handled by the underlying parser; 078 // it checks that the transferred document is in fact a JSON document, 079 // and that the "keys" field is present. 080 return JWKSet.parse(resource.getContent()); 081 082 } catch (Exception e) { 083 // Guard against unexpected exceptions 084 throw new JWKSetParseException("Unable to parse JWK set", e); 085 } 086 } 087 088 089 @Override 090 public void close() throws IOException { 091 // do nothing 092 } 093}