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