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}