001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyrighted [year] [name of copyright owner]".
013 *
014 * Copyright 2013-2015 ForgeRock AS.
015 */
016
017package org.forgerock.json.jose.jwk;
018
019import java.io.IOException;
020import java.util.List;
021import java.util.Map;
022
023import org.forgerock.json.JsonException;
024import org.forgerock.json.JsonValue;
025import org.forgerock.json.jose.jwt.JWObject;
026import org.forgerock.util.encode.Base64;
027
028import com.fasterxml.jackson.databind.ObjectMapper;
029
030/**
031 * The abstract base class for the 3 implementations of JWK.
032 */
033public abstract class JWK extends JWObject {
034    /**
035     * The KeyType key.
036     */
037    protected static final String KTY = "kty";
038
039    /**
040     * The KeyUse key.
041     */
042    protected static final String USE = "use";
043
044    /**
045     * The Algorithm key.
046     */
047    protected static final String ALG = "alg";
048
049    /**
050     * The KeyID key.
051     */
052    protected static final String KID = "kid";
053
054    /**
055     * The X509 URL key.
056     */
057    protected static final String X5U = "x5u";
058
059    /**
060     * The X509 thumbnail key.
061     */
062    protected static final String X5T = "x5t";
063
064    /**
065     * The X509 chain key.
066     */
067    protected static final String X5C = "x5c";
068
069    /**
070     * Creates a JWK given the basic parameters.
071     * @param kty the JWK key type
072     * @param use the JWK use
073     * @param alg the JWK algorithm
074     * @param kid the JWK key id
075     */
076    protected JWK(KeyType kty, KeyUse use, String alg, String kid) {
077        this(kty, use, alg, kid, null, null, null);
078    }
079
080    /**
081     * Creates a JWK given the basic parameters.
082     * @param kty the JWK key type
083     * @param use the JWK use
084     * @param alg the JWK algorithm
085     * @param kid the JWK key id
086     * @param x5u the x509 url for the key
087     * @param x5t the x509 thumbnail for the key
088     * @param x5c the x509 chain
089     */
090    protected JWK(KeyType kty, KeyUse use, String alg, String kid, String x5u, String x5t, List<Base64> x5c) {
091        super();
092        if (kty == null) {
093            new JsonException("kty is a required field");
094        }
095        put(KTY, kty.toString());
096        if (kid == null || kid.isEmpty()) {
097            new JsonException("kid is a required field");
098        }
099        put(KID, kid);
100        if (use != null) {
101            put(USE, use.toString());
102        }
103        if (alg != null && !alg.isEmpty()) {
104            put(ALG, alg);
105        }
106        if (x5c != null && !x5c.isEmpty()) {
107            put(X5C, x5c);
108        }
109        if (x5t != null && !x5t.isEmpty()) {
110            put(X5T, x5t);
111        }
112        if (x5u != null && !x5u.isEmpty()) {
113            put(X5U, x5u);
114        }
115    }
116
117    /**
118     * Gets the kty parameter of the JWK.
119     * @return A KeyType for the JWK
120     */
121    public KeyType getKeyType() {
122        return KeyType.getKeyType(get(KTY).asString());
123    }
124
125    /**
126     * Gets the use parameter of the JWK.
127     * @return A String representing the use parameter
128     */
129    public KeyUse getUse() {
130        return KeyUse.getKeyUse(get(USE).asString());
131    }
132
133    /**
134     * Gets the alg parameter of the JWK.
135     * @return A String representing the alg parameter
136     */
137    public String getAlgorithm() {
138        return get(ALG).asString();
139    }
140
141    /**
142     * Gets the kid parameter of the JWK.
143     * @return A String representing the kid parameter
144     */
145    public String getKeyId() {
146        return get(KID).asString();
147    }
148
149    /**
150     * Prints the JWK Object as a json string.
151     * @return A String representing JWK
152     */
153    public String toJsonString() {
154        return toString();
155    }
156
157    /**
158     * Parses a String into the proper JWK type.
159     *
160     * @param json The json String.
161     * @return A JWK object
162     * @throws org.forgerock.json.JsonException If there is a problem parsing the json String.
163     */
164    public static JWK parse(String json) {
165        JsonValue jwk = new JsonValue(toJsonValue(json));
166        return parse(jwk);
167    }
168
169    /**
170     * Parses a JsonValue into the proper JWK type.
171     *
172     * @param jwk The JsonValue Object.
173     * @return A JWK object
174     * @throws org.forgerock.json.JsonException If there is a problem parsing the json String.
175     */
176    public static JWK parse(JsonValue jwk) {
177        KeyType kty = KeyType.getKeyType(jwk.get(KTY).asString());
178
179        if (kty.equals(KeyType.RSA)) {
180            return RsaJWK.parse(jwk);
181        } else if (kty.equals(KeyType.OCT)) {
182            return OctJWK.parse(jwk);
183        } else if (kty.equals(KeyType.EC)) {
184            return EcJWK.parse(jwk);
185        } else {
186            throw new JsonException("Failed to parse json invalid kty parameter");
187        }
188    }
189
190    /**
191     * Converts a String into a JsonValue.
192     *
193     * @param json The json String.
194     * @return A JsonValue object.
195     * @throws org.forgerock.json.JsonException If there is a problem parsing the json String.
196     */
197    protected static JsonValue toJsonValue(String json) {
198        ObjectMapper mapper = new ObjectMapper();
199        try {
200            return new JsonValue(mapper.readValue(json, Map.class));
201        } catch (IOException e) {
202            throw new JsonException("Failed to parse json", e);
203        }
204    }
205
206    /**
207     * Gets the X509 URL.
208     * @return the url of the 509 cert header or null
209     */
210    public String getX509URL() {
211        return get(X5U).asString();
212    }
213
214    /**
215     * Gets the X509 thumbnail.
216     * @return Base64url of the X509 thumbnail
217     */
218    public String getX509Thumbnail() {
219        return get(X5T).asString();
220    }
221
222    /**
223     * Gets a List of base64 encoded chain certs.
224     * @return X509 Cert Chain
225     */
226    public List<Base64> getX509Chain() {
227        return get(X5C).asList(Base64.class);
228    }
229}