I am trying to implement token based authentication for a simple hello world program in JAX-RS with Grizzly.

I have set up a server and client class and a hello resource for displaying the hello world along with a parameter that is entered through a function in client class.

//This is the server class

import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;

import java.io.IOException;
import java.net.URI;
/**
 * Main class.
 *
 */
public class HelloServer extends TokenFilter{
    // Base URI the Grizzly HTTP server will listen on
    public static final String BASE_URI = "http://localhost:2000/";

    /**
     * Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
     * @return Grizzly HTTP server.
     */
    public static HttpServer startServer() {
        final TokenFilter tokenFilter = new TokenFilter();


        // create a resource config that scans for JAX-RS resources and providers
        final ResourceConfig rc = new ResourceConfig()
                                    .packages("com.example.assignment1")
                                    .register(tokenFilter);

        // create and start a new instance of grizzly http server
        // exposing the Jersey application at BASE_URI
        return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
    }

    /**
     * Main method.
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        final HttpServer server = startServer();
        System.out.printf("Jersey app started with endpoints available at "
                + "%s%nHit Ctrl-C to stop it...%n", BASE_URI);
        System.in.read();
        server.shutdown();
    }
}

This is the code for client class

import java.util.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import static com.example.assignment1.HelloServer.BASE_URI;

public class HelloClient {
    // Define the token to be used for authentication
    private static final String TOKEN = "your-jwt-token-here";
    public static void main(String[] args) throws IOException {

        pingHelloWorld("akshata");
        System.out.println("Program closing!");
    }
    private static void pingHelloWorld(String word) throws IOException {

        //URL url = new URL("http://localhost:2000/hello-world?name=" + word);

        URL url = new URL(BASE_URI + "hello-world?name=" + word);

        // Create a new HTTP connection

        HttpURLConnection http = (HttpURLConnection)url.openConnection();
        // Set the authorization header with the token
        http.setRequestProperty("Authorization", "Bearer " + TOKEN);

        // Print response headers
        Map<String, List<String>> headers = http.getHeaderFields();
        for (String key : headers.keySet()) {
            System.out.println(key + ": " + headers.get(key));
        }

        // Read the response from the server
        BufferedReader br = new BufferedReader(new InputStreamReader(http.getInputStream()));
        String response = br.readLine();
        System.out.printf("\n %s \n%n", response);
        http.disconnect();
    }
}

This is the code for resource class

import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Response;


@Path("/hello-world")

public class HelloResource {
    @GET
    @Produces("text/plain")
    @RolesAllowed("user")
    public String hello() {
        return "Hello, World!";
    }

    @GET
    @Path("/greet")
    @Produces("text/plain")
    @RolesAllowed("admin")

    public Response getHelloWorld(@QueryParam("name") String name) {
        String message = "Hello world " + name;
        return Response.status(200).entity(message).build();
    }
}

I am trying to implement token based authentication using JWT and have created a token provider class and token filter class

//This is token provider class 
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import jakarta.xml.bind.DatatypeConverter;

import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;
public class TokenProvider {

        private static final String SECRET_KEY = "mySecretKey12345";

        public static String generateToken(String subject, String issuer, long ttlMillis) {
            if (ttlMillis <= 0) {
                throw new RuntimeException("Expiry time must be greater than zero : [" + ttlMillis + "] ");
            }
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);

            //We will sign our JWT with our ApiKey secret

            byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SECRET_KEY);
            Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

            //set logging statement
            System.out.println(String.format("Generating token for subject: %s, issuer: %s, expiry: %d", subject, issuer, ttlMillis));

            //Let's set the JWT Claims
            JwtBuilder builder = Jwts.builder().setIssuedAt(now).setSubject(subject).setIssuer(issuer).signWith(signatureAlgorithm, signingKey);

            //if it has been specified, let's add the expiration
            Date exp = null;
            if (ttlMillis >= 0) {
                long expMillis = nowMillis + ttlMillis;
                exp = new Date(expMillis);
                builder.setExpiration(exp);
            }

            //Builds the JWT and serializes it to a compact, URL-safe string
            return builder.compact();

            /*return Jwts.builder()
                    .setSubject(subject)
                    .setIssuedAt(now)
                    .setExpiration(exp)
                    .signWith(signingKey, signatureAlgorithm)
                    .compact();*/
        }

        public static Claims validateToken(String token) {
            return Jwts.parser()
                    .setSigningKey(DatatypeConverter.parseBase64Binary(SECRET_KEY))
                    .parseClaimsJws(token).getBody();
        }
}
//This is token filter class
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.core.Response;

import java.io.IOException;

public class TokenFilter implements ContainerRequestFilter {
    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String AUTHORIZATION_PREFIX = "Bearer ";

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        String authorizationHeader = requestContext.getHeaderString(AUTHORIZATION_HEADER);
        if (authorizationHeader == null || !authorizationHeader.startsWith(AUTHORIZATION_PREFIX)) {
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
            return;
        }
        String token = authorizationHeader.substring(AUTHORIZATION_PREFIX.length());
        try {
            TokenProvider.validateToken(token);
        } catch (Exception e) {
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
        }
    }
}

I am getting an exception during runtime from client and have tried to check the logs on the server-side to verify that the token is being generated correctly and that it matches the token received by the client but I have no clue where i might be going wrong and have spent hours now trying to debug. Please could someone help me out with this.

0

There are 0 best solutions below