001/******************************************************************************* 002 * Copyright 2014 The MITRE Corporation 003 * and the MIT Kerberos and Internet Trust Consortium 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 *******************************************************************************/ 017package org.mitre.jwt.signer.service.impl; 018 019import java.security.NoSuchAlgorithmException; 020import java.security.spec.InvalidKeySpecException; 021import java.util.Map; 022import java.util.concurrent.ExecutionException; 023import java.util.concurrent.TimeUnit; 024 025import org.mitre.jwt.signer.service.JwtSigningAndValidationService; 026import org.mitre.oauth2.model.ClientDetailsEntity; 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029import org.springframework.stereotype.Service; 030 031import com.google.common.base.Strings; 032import com.google.common.cache.CacheBuilder; 033import com.google.common.cache.CacheLoader; 034import com.google.common.cache.LoadingCache; 035import com.google.common.collect.ImmutableMap; 036import com.google.common.util.concurrent.UncheckedExecutionException; 037import com.nimbusds.jose.jwk.JWK; 038import com.nimbusds.jose.jwk.KeyUse; 039import com.nimbusds.jose.jwk.OctetSequenceKey; 040import com.nimbusds.jose.util.Base64URL; 041 042/** 043 * Creates and caches symmetrical validators for clients based on client secrets. 044 * 045 * @author jricher 046 * 047 */ 048@Service 049public class SymmetricCacheService { 050 051 private static Logger logger = LoggerFactory.getLogger(SymmetricCacheService.class); 052 053 private LoadingCache<String, JwtSigningAndValidationService> validators; 054 055 056 public SymmetricCacheService() { 057 validators = CacheBuilder.newBuilder() 058 .expireAfterAccess(24, TimeUnit.HOURS) 059 .maximumSize(100) 060 .build(new SymmetricValidatorBuilder()); 061 } 062 063 064 /** 065 * Create a symmetric signing and validation service for the given client 066 * 067 * @param client 068 * @return 069 */ 070 public JwtSigningAndValidationService getSymmetricValidtor(ClientDetailsEntity client) { 071 072 if (client == null) { 073 logger.error("Couldn't create symmetric validator for null client"); 074 return null; 075 } 076 077 if (Strings.isNullOrEmpty(client.getClientSecret())) { 078 logger.error("Couldn't create symmetric validator for client " + client.getClientId() + " without a client secret"); 079 return null; 080 } 081 082 try { 083 return validators.get(client.getClientSecret()); 084 } catch (UncheckedExecutionException ue) { 085 logger.error("Problem loading client validator", ue); 086 return null; 087 } catch (ExecutionException e) { 088 logger.error("Problem loading client validator", e); 089 return null; 090 } 091 092 } 093 094 public class SymmetricValidatorBuilder extends CacheLoader<String, JwtSigningAndValidationService> { 095 @Override 096 public JwtSigningAndValidationService load(String key) throws Exception { 097 try { 098 099 String id = "SYMMETRIC-KEY"; 100 101 JWK jwk = new OctetSequenceKey(Base64URL.encode(key), KeyUse.SIGNATURE, null, null, id, null, null, null); 102 Map<String, JWK> keys = ImmutableMap.of(id, jwk); 103 JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keys); 104 105 return service; 106 107 } catch (NoSuchAlgorithmException e) { 108 logger.error("Couldn't create symmetric validator for client", e); 109 } catch (InvalidKeySpecException e) { 110 logger.error("Couldn't create symmetric validator for client", e); 111 } 112 113 throw new IllegalArgumentException("Couldn't create symmetric validator for client"); 114 } 115 116 } 117 118}