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

io.polyglotted.esjwt.impl.JsonWebToken Maven / Gradle / Ivy

There is a newer version: 6.2.4
Show newest version
/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch 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.polyglotted.esjwt.impl;

import org.elasticsearch.xpack.core.security.user.User;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import static io.polyglotted.esjwt.impl.CommonUtil.asTime;
import static io.polyglotted.esjwt.impl.CommonUtil.deepGet;
import static io.polyglotted.esjwt.impl.CommonUtil.parseJson;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Locale.ENGLISH;
import static org.apache.commons.codec.binary.Base64.decodeBase64;

public final class JsonWebToken {
    private static Pattern EMAIL_REGEX = Pattern.compile("(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]" +
        "+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(" +
        "?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[0" +
        "1]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[A-Za-z0-9-]*[A-Za-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\" +
        "x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])");
    private final Map header;
    private final Map payload;
    private final byte[] contentBytes;
    private final byte[] signatureBytes;

    private JsonWebToken(Map header, Map payload, byte[] contentBytes, byte[] signatureBytes) {
        this.header = header; this.payload = payload; this.contentBytes = contentBytes; this.signatureBytes = signatureBytes;
    }

    public static JsonWebToken parseJwt(String token) throws IOException {
        String[] parts = token.split("\\.");
        if (parts.length != 3) { throw new IllegalArgumentException("invalid token parts"); }
        return new JsonWebToken(parseJson(decodeBase64(parts[0])), parseJson(decodeBase64(parts[1])),
            String.format(ENGLISH, "%s.%s", parts[0], parts[1]).getBytes(UTF_8), decodeBase64(parts[2]));
    }

    String keyCode() { return deepGet(header, "alg") + ":" + deepGet(header, "kid"); }

    byte[] contentBytes() { return this.contentBytes; }

    byte[] signatureBytes() { return this.signatureBytes; }

    Long expiresAt() { return asTime(payload, "exp"); }

    Long notBefore() { return asTime(payload, "nbf"); }

    Long issuedAt() { return asTime(payload, "iat"); }

    User buildUser(String groupsField) {
        return new User(userId(payload), groupsToRoles(payload, groupsField), null, email(payload), payload, true);
    }

    @SuppressWarnings("unchecked") private static String[] groupsToRoles(Map claims, String groupsField) {
        List roles = new LinkedList<>();
        roles.add("jwt_user");
        if(claims.containsKey(groupsField)) {
            List groups = (List) claims.get(groupsField);
            for(String group : groups) { roles.add(group.toLowerCase(ENGLISH)); }
        }
        return roles.toArray(new String[roles.size()]);
    }

    private static String userId(Map claims) { return (String) claims.getOrDefault("uid", claims.get("sub")); }

    private static String email(Map claims) {
        String email = (String) claims.getOrDefault("sub", ""); return EMAIL_REGEX.matcher(email).matches() ? email : null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy