1

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.

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
ash
  • 41
  • 1
  • Have you checked to see if there is any exception with the TokenProvider.validateToken() call? If there is an exception, you are aborting with 401, but you have no idea what the exception is, based on your code. I would check that first. – Paul Samsotha Mar 18 '23 at 17:18

0 Answers0