001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2021, 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.oauth2.sdk.dpop; 019 020 021import java.util.AbstractMap; 022import java.util.Map; 023import java.util.Objects; 024 025import net.jcip.annotations.Immutable; 026import net.minidev.json.JSONObject; 027 028import com.nimbusds.jose.JOSEException; 029import com.nimbusds.jose.jwk.JWK; 030import com.nimbusds.jose.util.Base64URL; 031import com.nimbusds.jwt.JWTClaimsSet; 032import com.nimbusds.oauth2.sdk.ParseException; 033import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 034 035 036/** 037 * JSON Web Key (JWK) SHA-256 thumbprint confirmation. 038 */ 039@Immutable 040public final class JWKThumbprintConfirmation { 041 042 043 /** 044 * The JWK SHA-256 thumbprint. 045 */ 046 private final Base64URL jkt; 047 048 049 /** 050 * Creates a new JWK SHA-256 thumbprint. 051 * 052 * @param jkt The JWK SHA-256 thumbprint. Must not be {@code null}. 053 */ 054 public JWKThumbprintConfirmation(final Base64URL jkt) { 055 056 if (jkt == null) { 057 throw new IllegalArgumentException("The JWK thumbprint must not be null"); 058 } 059 060 this.jkt = jkt; 061 } 062 063 064 /** 065 * Returns the JWK SHA-256 thumbprint. 066 * 067 * @return The JWK SHA-256 thumbprint. 068 */ 069 public Base64URL getValue() { 070 071 return jkt; 072 } 073 074 075 /** 076 * Returns this JWK SHA-256 thumbprint confirmation as a JSON object. 077 * 078 * <p>Example: 079 * 080 * <pre> 081 * { 082 * "cnf" : { "jkt" : "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I" } 083 * } 084 * </pre> 085 * 086 * @return The JSON object. 087 */ 088 public JSONObject toJSONObject() { 089 090 JSONObject jsonObject = new JSONObject(); 091 Map.Entry<String,JSONObject> cnfClaim = toJWTClaim(); 092 jsonObject.put(cnfClaim.getKey(), cnfClaim.getValue()); 093 return jsonObject; 094 } 095 096 097 /** 098 * Returns this JWK SHA-256 thumbprint confirmation as a JWT claim. 099 * 100 * <p>Example: 101 * 102 * <pre> 103 * "cnf" : { "jkt" : "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I" } 104 * </pre> 105 * 106 * @return The JWT claim name / value. 107 */ 108 public Map.Entry<String,JSONObject> toJWTClaim() { 109 110 JSONObject cnf = new JSONObject(); 111 cnf.put("jkt", jkt.toString()); 112 113 return new AbstractMap.SimpleImmutableEntry<>( 114 "cnf", 115 cnf 116 ); 117 } 118 119 120 /** 121 * Applies this JWK SHA-256 thumbprint confirmation to the specified 122 * JWT claims set. 123 * 124 * @param jwtClaimsSet The JWT claims set. 125 * 126 * @return The modified JWT claims set. 127 */ 128 public JWTClaimsSet applyTo(final JWTClaimsSet jwtClaimsSet) { 129 130 Map.Entry<String,JSONObject> cnfClaim = toJWTClaim(); 131 132 return new JWTClaimsSet.Builder(jwtClaimsSet) 133 .claim(cnfClaim.getKey(), cnfClaim.getValue()) 134 .build(); 135 } 136 137 138 @Override 139 public String toString() { 140 return toJSONObject().toJSONString(); 141 } 142 143 144 @Override 145 public boolean equals(Object o) { 146 if (this == o) return true; 147 if (!(o instanceof JWKThumbprintConfirmation)) return false; 148 JWKThumbprintConfirmation that = (JWKThumbprintConfirmation) o; 149 return jkt.equals(that.jkt); 150 } 151 152 153 @Override 154 public int hashCode() { 155 return Objects.hash(jkt); 156 } 157 158 159 /** 160 * Parses a JWK SHA-256 thumbprint confirmation from the specified JWT 161 * claims set. 162 * 163 * @param jwtClaimsSet The JWT claims set. 164 * 165 * @return The JWK SHA-256 thumbprint confirmation, {@code null} if not 166 * found. 167 */ 168 public static JWKThumbprintConfirmation parse(final JWTClaimsSet jwtClaimsSet) { 169 170 Map<String, Object> jsonObjectClaim; 171 try { 172 jsonObjectClaim = jwtClaimsSet.getJSONObjectClaim("cnf"); 173 } catch (java.text.ParseException e) { 174 return null; 175 } 176 177 if (jsonObjectClaim == null) { 178 return null; 179 } 180 181 return parseFromConfirmationJSONObject(new JSONObject(jsonObjectClaim)); 182 } 183 184 185 /** 186 * Parses a JWK SHA-256 thumbprint confirmation from the specified JSON 187 * object representation of a JWT claims set. 188 * 189 * @param jsonObject The JSON object. 190 * 191 * @return The JWK SHA-256 thumbprint confirmation, {@code null} if not 192 * found. 193 */ 194 public static JWKThumbprintConfirmation parse(final JSONObject jsonObject) { 195 196 if (! jsonObject.containsKey("cnf")) { 197 return null; 198 } 199 200 try { 201 return parseFromConfirmationJSONObject(JSONObjectUtils.getJSONObject(jsonObject, "cnf")); 202 } catch (ParseException e) { 203 return null; 204 } 205 } 206 207 208 /** 209 * Parses a JWK SHA-256 thumbprint confirmation from the specified 210 * confirmation ("cnf") JSON object. 211 * 212 * @param cnf The confirmation JSON object, {@code null} if none. 213 * 214 * @return The JWK SHA-256 thumbprint confirmation, {@code null} if not 215 * found. 216 */ 217 public static JWKThumbprintConfirmation parseFromConfirmationJSONObject(final JSONObject cnf) { 218 219 if (cnf == null) { 220 return null; 221 } 222 223 try { 224 String jktString = JSONObjectUtils.getString(cnf, "jkt"); 225 return new JWKThumbprintConfirmation(new Base64URL(jktString)); 226 } catch (ParseException e) { 227 return null; 228 } 229 } 230 231 232 /** 233 * Creates a confirmation of the specified JWK. 234 * 235 * @param jwk The JWK. 236 * 237 * @return The JWK SHA-256 thumbprint confirmation. 238 * 239 * @throws JOSEException If the thumbprint computation failed. 240 */ 241 public static JWKThumbprintConfirmation of(final JWK jwk) 242 throws JOSEException { 243 244 return new JWKThumbprintConfirmation(jwk.computeThumbprint()); 245 } 246}