All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cloudfoundry.identity.uaa.oauth.jwk.JsonWebKey Maven / Gradle / Ivy

There is a newer version: 4.30.0
Show newest version
/*
 * ****************************************************************************
 *     Cloud Foundry
 *     Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
 *
 *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
 *     You may not use this product except in compliance with the License.
 *
 *     This product includes a number of subcomponents with
 *     separate copyright notices and license terms. Your use of these
 *     subcomponents is subject to the terms and conditions of the
 *     subcomponent's license, as noted in the LICENSE file.
 * ****************************************************************************
 */

package org.cloudfoundry.identity.uaa.oauth.jwk;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.apache.commons.codec.binary.Base64;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static org.cloudfoundry.identity.uaa.oauth.jwk.JsonWebKey.KeyType.MAC;
import static org.cloudfoundry.identity.uaa.oauth.jwk.JsonWebKey.KeyType.RSA;
import static org.springframework.util.StringUtils.hasText;

/**
 * See https://tools.ietf.org/html/rfc7517
 */

@JsonDeserialize(using = JsonWebKeyDeserializer.class)
@JsonSerialize(using = JsonWebKeySerializer.class)
public class JsonWebKey {


    public enum KeyUse {
        sig,
        enc
    }

    public enum KeyType {
        RSA,
        MAC
    }

    public enum KeyOperation {
        sign,
        verify,
        encrypt,
        decrypt,
        wrapKey,
        unwrapKey,
        deriveKey,
        deriveBits
    }

    public static String KID = "kid";
    public static String KTY = "kty";
    public static String ALG = "alg";

    private final Map json;

    public JsonWebKey(Map json) {
        if (json.get("kty") == null) {
            throw new IllegalArgumentException("kty field is required");
        }
        KeyType.valueOf((String) json.get("kty"));
        this.json = new HashMap(json);
    }

    public Map getKeyProperties() {
        return Collections.unmodifiableMap(json);
    }

    public final KeyType getKty() {
        return KeyType.valueOf((String) getKeyProperties().get(KTY));
    }

    public final String getKid() {
        return (String) getKeyProperties().get(KID);
    }

    public JsonWebKey setKid(String kid) {
        this.json.put(KID, kid);
        return this;
    }

    public final KeyUse getUse() {
        String use = (String) getKeyProperties().get("use");
        KeyUse result = null;
        if (hasText(use)) {
            result = KeyUse.valueOf(use);
        }
        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof JsonWebKey)) return false;
        JsonWebKey that = (JsonWebKey) o;
        return getKid() != null ? getKid().equals(that.getKid()) : that.getKid() == null && getKeyProperties().equals(that.getKeyProperties());
    }

    @Override
    public int hashCode() {
        if (getKid() == null) {
            return getKty().hashCode();
        } else {
            return getKid().hashCode();
        }
    }

    //helper methods
    public String getAlgorithm() {
        return (String) getKeyProperties().get(ALG);
    }

    public String getValue() {
        String result = (String) getKeyProperties().get("value");
        if (result == null) {
            if (RSA.equals(getKty())) {
                result = pemEncodePublicKey(getRsaPublicKey(this));
                this.json.put("value", result);
            } else if (MAC.equals(getKty())) {
                result = (String) getKeyProperties().get("k");
                this.json.put("value", result);
            }
        }
        return result;
    }

    public Set getKeyOps() {
        List result = (List) getKeyProperties().get("key_ops");
        if (result==null) {
            result = Collections.emptyList();
        }
        return result.stream().map(o -> KeyOperation.valueOf(o)).collect(Collectors.toSet());
    }

    public static String pemEncodePublicKey(PublicKey publicKey) {
        String begin = "-----BEGIN PUBLIC KEY-----\n";
        String end = "\n-----END PUBLIC KEY-----";
        byte[] data = publicKey.getEncoded();
        String base64encoded = new String(new Base64(false).encode(data));
        return begin + base64encoded + end;
    }

    public static PublicKey getRsaPublicKey(JsonWebKey key) {
        final Base64 decoder = new Base64(true);
        String e = (String) key.getKeyProperties().get("e");
        String n = (String) key.getKeyProperties().get("n");
        BigInteger modulus = new BigInteger(1, decoder.decode(n.getBytes(StandardCharsets.UTF_8)));
        BigInteger exponent = new BigInteger(1, decoder.decode(e.getBytes(StandardCharsets.UTF_8)));
        try {
            return KeyFactory.getInstance("RSA").generatePublic(
                new RSAPublicKeySpec(modulus, exponent)
            );
        } catch (InvalidKeySpecException | NoSuchAlgorithmException e1) {
            throw new IllegalStateException(e1);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy