001/******************************************************************************* 002 * Copyright 2017 The MIT Internet Trust Consortium 003 * 004 * Portions copyright 2011-2013 The MITRE Corporation 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the 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 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 *******************************************************************************/ 018package org.mitre.openid.connect.client.keypublisher; 019 020import java.util.Map; 021import java.util.UUID; 022 023import org.mitre.jwt.signer.service.JWTSigningAndValidationService; 024import org.mitre.openid.connect.view.JWKSetView; 025import org.springframework.beans.BeansException; 026import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 027import org.springframework.beans.factory.support.BeanDefinitionBuilder; 028import org.springframework.beans.factory.support.BeanDefinitionRegistry; 029import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; 030import org.springframework.web.servlet.ModelAndView; 031 032import com.google.common.base.Strings; 033import com.nimbusds.jose.jwk.JWK; 034 035/** 036 * @author jricher 037 * 038 */ 039public class ClientKeyPublisher implements BeanDefinitionRegistryPostProcessor { 040 041 private JWTSigningAndValidationService signingAndValidationService; 042 043 private String jwkPublishUrl; 044 045 private BeanDefinitionRegistry registry; 046 047 private String jwkViewName = JWKSetView.VIEWNAME; 048 049 /** 050 * If the jwkPublishUrl field is set on this bean, set up a listener on that URL to publish keys. 051 */ 052 @Override 053 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { 054 if (!Strings.isNullOrEmpty(getJwkPublishUrl())) { 055 056 // add a mapping to this class 057 BeanDefinitionBuilder clientKeyMapping = BeanDefinitionBuilder.rootBeanDefinition(ClientKeyPublisherMapping.class); 058 // custom view resolver 059 BeanDefinitionBuilder viewResolver = BeanDefinitionBuilder.rootBeanDefinition(JwkViewResolver.class); 060 061 if (!Strings.isNullOrEmpty(getJwkPublishUrl())) { 062 clientKeyMapping.addPropertyValue("jwkPublishUrl", getJwkPublishUrl()); 063 064 // randomize view name to make sure it doesn't conflict with local views 065 jwkViewName = JWKSetView.VIEWNAME + "-" + UUID.randomUUID().toString(); 066 viewResolver.addPropertyValue("jwkViewName", jwkViewName); 067 068 // view bean 069 BeanDefinitionBuilder jwkView = BeanDefinitionBuilder.rootBeanDefinition(JWKSetView.class); 070 registry.registerBeanDefinition(JWKSetView.VIEWNAME, jwkView.getBeanDefinition()); 071 viewResolver.addPropertyReference("jwk", JWKSetView.VIEWNAME); 072 } 073 074 registry.registerBeanDefinition("clientKeyMapping", clientKeyMapping.getBeanDefinition()); 075 registry.registerBeanDefinition("jwkViewResolver", viewResolver.getBeanDefinition()); 076 077 } 078 079 } 080 081 /* (non-Javadoc) 082 * @see org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(org.springframework.beans.factory.support.BeanDefinitionRegistry) 083 */ 084 @Override 085 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { 086 this.registry = registry; 087 } 088 089 /** 090 * Return a view to publish all keys in JWK format. Only used if jwkPublishUrl is set. 091 * @return 092 */ 093 public ModelAndView publishClientJwk() { 094 095 // map from key id to key 096 Map<String, JWK> keys = signingAndValidationService.getAllPublicKeys(); 097 098 return new ModelAndView(jwkViewName, "keys", keys); 099 } 100 101 /** 102 * @return the jwkPublishUrl 103 */ 104 public String getJwkPublishUrl() { 105 return jwkPublishUrl; 106 } 107 108 /** 109 * @param jwkPublishUrl the jwkPublishUrl to set 110 */ 111 public void setJwkPublishUrl(String jwkPublishUrl) { 112 this.jwkPublishUrl = jwkPublishUrl; 113 } 114 115 /** 116 * @return the signingAndValidationService 117 */ 118 public JWTSigningAndValidationService getSigningAndValidationService() { 119 return signingAndValidationService; 120 } 121 122 /** 123 * @param signingAndValidationService the signingAndValidationService to set 124 */ 125 public void setSigningAndValidationService(JWTSigningAndValidationService signingAndValidationService) { 126 this.signingAndValidationService = signingAndValidationService; 127 } 128 129 130}