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

io.cellery.security.extensions.jwt.CellerySignedJWTBuilder Maven / Gradle / Ivy

There is a newer version: 0.6.0
Show newest version
/*
 *  Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you under the Apache License,
 *  Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */

package io.cellery.security.extensions.jwt;

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import io.cellery.security.extensions.exception.CelleryAuthException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;

import java.security.Key;
import java.security.interfaces.RSAPrivateKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * The JWT token builder for Cellery.
 */
public class CellerySignedJWTBuilder {

    private static final String TENANT_DOMAIN = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
    private static final int TENANT_ID = MultitenantConstants.SUPER_TENANT_ID;

    private static final String MICRO_GATEWAY_DEFAULT_AUDIENCE_VALUE = "http://io.cellery.apimgt/gateway";
    private static final String CELLERY_STS_ISSUER_CONFIG = "Cellery.STS.Issuer";
    private static final String DEFAULT_ISSUER_VALUE = "https://sts.cellery.io";
    private static final String SCOPE_CLAIM = "scope";
    private static final String KEY_TYPE_CLAIM = "keytype";
    private static final String PRODUCTION_KEY_TYPE = "PRODUCTION";

    private JWSHeader.Builder headerBuilder = new JWSHeader.Builder(JWSAlgorithm.RS256);
    private JWTClaimsSet.Builder claimSetBuilder = new JWTClaimsSet.Builder();

    // By default we set the expiry to be 20mins (So that it will be greater than GatewayCache timeout)
    private long expiryInSeconds = 1200L;
    private List audience = new ArrayList<>();

    public CellerySignedJWTBuilder subject(String subject) {

        claimSetBuilder.subject(subject);
        return this;
    }

    public CellerySignedJWTBuilder claim(String name, Object value) {

        claimSetBuilder.claim(name, value);
        return this;
    }

    public CellerySignedJWTBuilder claims(Map customClaims) {

        customClaims.forEach((x, y) -> claimSetBuilder.claim(x, y));
        return this;
    }

    public CellerySignedJWTBuilder scopes(List scopes) {

        return claim(SCOPE_CLAIM, scopes);
    }

    public CellerySignedJWTBuilder expiryInSeconds(long expiryInSeconds) {

        this.expiryInSeconds = expiryInSeconds;
        return this;
    }

    public CellerySignedJWTBuilder audience(List audience) {

        this.audience = audience;
        return this;
    }

    public CellerySignedJWTBuilder audience(String audience) {

        this.audience.add(audience);
        return this;
    }

    private JWSHeader buildJWSHeader() throws IdentityOAuth2Exception {

        String certThumbPrint = OAuth2Util.getThumbPrint(TENANT_DOMAIN, TENANT_ID);
        headerBuilder.keyID(certThumbPrint);
        headerBuilder.x509CertThumbprint(new Base64URL(certThumbPrint));
        return headerBuilder.build();
    }

    public String build() throws CelleryAuthException {

        // Build the JWT Header
        try {
            JWSHeader jwsHeader = buildJWSHeader();
            // Add mandatory claims
            addMandatoryClaims(claimSetBuilder);
            JWTClaimsSet claimsSet = this.claimSetBuilder.build();

            SignedJWT signedJWT = new SignedJWT(jwsHeader, claimsSet);
            JWSSigner signer = new RSASSASigner(getRSASigningKey());

            signedJWT.sign(signer);
            return signedJWT.serialize();
        } catch (IdentityOAuth2Exception | JOSEException e) {
            throw new CelleryAuthException("Error while generating the signed JWT.", e);
        }
    }

    private void addMandatoryClaims(JWTClaimsSet.Builder claimsSet) {

        Date issuedAt = new Date(System.currentTimeMillis());
        Date expiryTime = new Date(issuedAt.getTime() + expiryInSeconds * 1000);

        List audience = getAudience(this.audience);

        claimsSet.jwtID(UUID.randomUUID().toString())
                .issuer(getIssuer())
                .issueTime(issuedAt)
                .expirationTime(expiryTime)
                .audience(audience)
                .claim(KEY_TYPE_CLAIM, PRODUCTION_KEY_TYPE);
    }

    private String getIssuer() {

        String issuer = IdentityUtil.getProperty(CELLERY_STS_ISSUER_CONFIG);
        if (StringUtils.isEmpty(issuer)) {
            issuer = DEFAULT_ISSUER_VALUE;
        }
        return issuer;
    }

    private RSAPrivateKey getRSASigningKey() throws IdentityOAuth2Exception {

        Key privateKey = OAuth2Util.getPrivateKey(TENANT_DOMAIN, TENANT_ID);
        return (RSAPrivateKey) privateKey;
    }

    private List getAudience(List audience) {

        if (CollectionUtils.isEmpty(audience)) {
            return Collections.singletonList(MICRO_GATEWAY_DEFAULT_AUDIENCE_VALUE);
        } else {
            return audience.stream()
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.toList());
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy