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

com.jetdrone.vertx.yoke.middleware.JWT Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.Yoke;
import com.jetdrone.vertx.yoke.core.YokeException;
import org.jetbrains.annotations.NotNull;
import org.vertx.java.core.Handler;
import org.vertx.java.core.json.JsonObject;

import java.util.regex.Pattern;

public class JWT extends Middleware {

    private static final Pattern BEARER = Pattern.compile("^Bearer$", Pattern.CASE_INSENSITIVE);

    public interface JWTHandler {
        public void handle(JsonObject token, Handler result);
    }

    private final String skip;

    private com.jetdrone.vertx.yoke.security.JWT jwt;

    private final JWTHandler handler;

    public JWT() {
        this.skip = null;
        this.handler = null;
    }

    public JWT(final @NotNull String skip) {
        this.skip = skip;
        this.handler = null;
    }

    public JWT(final @NotNull String skip, final @NotNull JWTHandler handler) {
        this.skip = skip;
        this.handler = handler;
    }

    public JWT(final @NotNull JWTHandler handler) {
        this.skip = null;
        this.handler = handler;
    }

    @Override
    public Middleware init(@NotNull final Yoke yoke, @NotNull final String mount) {
        super.init(yoke, mount);

        jwt = new com.jetdrone.vertx.yoke.security.JWT(yoke.security());
        return this;
    }

    @Override
    public void handle(@NotNull final YokeRequest request, @NotNull final Handler next) {
        String token = null;

        if ("OPTIONS".equals(request.method()) && request.getHeader("access-control-request-headers") != null) {
            for (String ctrlReq : request.getHeader("access-control-request-headers").split(",")) {
                if (ctrlReq.contains("authorization")) {
                    next.handle(null);
                    return;
                }
            }
        }

        if (skip != null && skip.contains(request.normalizedPath())) {
            next.handle(null);
            return;
        }

        final String authorization = request.getHeader("authorization");

        if (authorization != null) {
            String[] parts = authorization.split(" ");
            if (parts.length == 2) {
                final String scheme = parts[0],
                             credentials = parts[1];

                if (BEARER.matcher(scheme).matches()) {
                    token = credentials;
                }
            } else {
                next.handle(new YokeException(401, "Format is Authorization: Bearer [token]"));
                return;
            }
        } else {
            next.handle(new YokeException(401, "No Authorization header was found"));
            return;
        }

        try {
            final JsonObject jwtToken = jwt.decode(token);

            // All dates in JWT are of type NumericDate
            // a NumericDate is: numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until
            // the specified UTC date/time, ignoring leap seconds
            final long now = System.currentTimeMillis() / 1000;

            if (jwtToken.containsField("iat")) {
                Long iat = jwtToken.getLong("iat");
                // issue at must be in the past
                if (iat > now) {
                    next.handle(new YokeException(401, "Invalid Token!"));
                    return;
                }
            }

            if (jwtToken.containsField("nbf")) {
                Long nbf = jwtToken.getLong("nbf");
                // not before must be after now
                if (nbf > now) {
                    next.handle(new YokeException(401, "Invalid Token!"));
                    return;
                }
            }

            if (jwtToken.containsField("exp")) {
                Long exp = jwtToken.getLong("exp");
                // expires must be after now
                if (now > exp) {
                    next.handle(new YokeException(401, "Invalid Token!"));
                    return;
                }
            }
            request.put("jwt", jwtToken);

            if (handler == null) {
                next.handle(null);
                return;
            }

            handler.handle(jwtToken, next);
        } catch (RuntimeException e) {
            next.handle(new YokeException(401, e));
        }
    }
}