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.