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.AbstractMap;
024import java.util.Map;
025
026import com.nimbusds.jose.util.Base64URL;
027import com.nimbusds.jose.util.JSONObjectUtils;
028import com.nimbusds.jose.util.X509CertUtils;
029import com.nimbusds.jwt.JWTClaimsSet;
030import net.jcip.annotations.Immutable;
031import net.minidev.json.JSONObject;
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 AbstractMap.SimpleImmutableEntry<>(
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 String toString() {
139                return toJSONObject().toJSONString();
140        }
141        
142        
143        @Override
144        public boolean equals(final Object o) {
145                if (this == o) return true;
146                if (!(o instanceof X509CertificateConfirmation)) return false;
147                X509CertificateConfirmation that = (X509CertificateConfirmation) o;
148                return x5tS256 != null ? x5tS256.equals(that.x5tS256) : that.x5tS256 == null;
149        }
150        
151        
152        @Override
153        public int hashCode() {
154                return x5tS256 != null ? x5tS256.hashCode() : 0;
155        }
156        
157        
158        /**
159         * Parses a X.509 certificate confirmation from the specified JWT
160         * claims set.
161         *
162         * @param jwtClaimsSet The JWT claims set.
163         *
164         * @return The X.509 certificate confirmation, {@code null} if not
165         *         found.
166         */
167        public static X509CertificateConfirmation parse(final JWTClaimsSet jwtClaimsSet) {
168                
169                JSONObject cnf;
170                try {
171                        cnf = jwtClaimsSet.getJSONObjectClaim("cnf");
172                } catch (ParseException e) {
173                        return null;
174                }
175                
176                return parseFromConfirmationJSONObject(cnf);
177        }
178        
179        
180        /**
181         * Parses a X.509 certificate confirmation from the specified JSON
182         * object representation of a JWT claims set.
183         *
184         * @param jsonObject The JSON object.
185         *
186         * @return The X.509 certificate confirmation, {@code null} if not
187         *         found.
188         */
189        public static X509CertificateConfirmation parse(final JSONObject jsonObject) {
190                
191                if (! jsonObject.containsKey("cnf")) {
192                        return null;
193                }
194                
195                try {
196                        return parseFromConfirmationJSONObject(JSONObjectUtils.getJSONObject(jsonObject, "cnf"));
197                } catch (ParseException e) {
198                        return null;
199                }
200        }
201        
202        
203        /**
204         * Parses a X.509 certificate confirmation from the specified
205         * confirmation ("cnf") JSON object.
206         *
207         * @param cnf The confirmation JSON object, {@code null} if none.
208         *
209         * @return The X.509 certificate confirmation, {@code null} if not
210         *         found.
211         */
212        public static X509CertificateConfirmation parseFromConfirmationJSONObject(final JSONObject cnf) {
213                
214                if (cnf == null) {
215                        return null;
216                }
217                
218                try {
219                        String x5tString = JSONObjectUtils.getString(cnf, "x5t#S256");
220                        
221                        if (x5tString == null) {
222                                return null;
223                        }
224                        
225                        return new X509CertificateConfirmation(new Base64URL(x5tString));
226                        
227                } catch (ParseException e) {
228                        return null;
229                }
230        }
231        
232        
233        /**
234         * Creates a confirmation of the specified X.509 certificate.
235         *
236         * @param x509Cert The X.509 certificate.
237         *
238         * @return The X.509 certificate confirmation.
239         */
240        public static X509CertificateConfirmation of(final X509Certificate x509Cert) {
241                
242                return new X509CertificateConfirmation(X509CertUtils.computeSHA256Thumbprint(x509Cert));
243        }
244}