how to enable https from java application - java

I am using core java for my rest service. Based on my requirement I cannot use spring boot for rest endpoint.
I achieved implementing http endpoint from core java.
But I cannot enable HTTPS via core java application.
I have .p12 file with me. Is there any way to enable HTTPS for Core java application ?
Below is my code
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpServer;
public class Sample {
public static void main(String[] args) {
try {
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
server.createContext("/endpoint", new CustomHttpHandler());
server.setExecutor(null);
server.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
CustomHttpHandler
import java.io.IOException;
import java.io.OutputStream;
import com.sun.net.httpserver.*;
public class CustomHttpHandler implements HttpHandler {
#Override
public void handle(HttpExchange res) throws IOException {
String response = "Response from server";
res.sendResponseHeaders(200, response.length());
OutputStream outputStream = res.getResponseBody();
outputStream.write(response.getBytes());
outputStream.close();
}
}

Related

Separate Grizzly HTTPHandlers for different verbs on same URL

I would like to handle a variety of HTTP methods on the same URL. i.e
GET http://localhost:8081/test
POST http://localhost:8081/test
I was originally thinking I could create a separate HTTPHandler for each method, but what I'm not clear on is how to route the request to the correct handler. Is there some filter higher up that I'm missing? I'm currently adding multiple HTTPHandlers to the server configuration, but only the first handler is being called.
Or do I have the wrong idea? Should I be using a single HTTPHandler for all requests to the same path and just check the HTTP method and respond accordingly?
import java.net.URI;
import javax.ws.rs.client.ClientBuilder;
import org.glassfish.grizzly.http.Method;
import org.glassfish.grizzly.http.server.HttpHandler;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.grizzly.http.server.Response;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
public class HttpHandlerTest
{
private static final URI BASE_URI = URI.create("http://localhost:8081");
private static final String MAPPING = "/test";
public static void main(String[] args)
{
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(BASE_URI, (GrizzlyHttpContainer) null, false, null, true);
server.getServerConfiguration().addHttpHandler(new GetHandler(), MAPPING);
server.getServerConfiguration().addHttpHandler(new PostHandler(), MAPPING);
javax.ws.rs.core.Response getResponse = ClientBuilder.newClient().target(BASE_URI + MAPPING).request().get();
System.out.println(getResponse.readEntity(String.class));
javax.ws.rs.core.Response postResponse = ClientBuilder.newClient().target(BASE_URI + MAPPING).request().post(null);
System.out.println(postResponse.readEntity(String.class));
server.shutdown();
}
public static class GetHandler extends HttpHandler{
#Override
public void service(Request request, Response response) throws Exception{
if (request.getMethod() == Method.GET){
// handle GET only, move on if method is something else
response.getWriter().write("GET response");
}
else
{
// let another HTTPHandler handle this
response.getWriter().write("I wanted a different handler to handle this");
}
}
}
public static class PostHandler extends HttpHandler{
#Override
public void service(Request request, Response response) throws Exception{
if (request.getMethod() == Method.POST){
// handle GET only, move on if method is something else
response.getWriter().write("POST response");
}
}
}
}

Spring security oauth2 - add filter after oauth/token call

I am using Spring Boot 2.1.1.RELEASE (spring-security-oauth2-2.3.4.RELEASE).
I would like to create a filter with precedence after TokenEndpoint#postAccessToken call. Why ? 'cause in that filter I want to take the token from the tokenStore and add it as a cookie to the response.
I would expect that, this will give me what I want:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.(...)
.addFilterAfter(new MyFilter(), BasicAuthenticationFilter.class);
}
But it doesn't. I can see, that BasicAuthenticationFilter is called after successfull authentication on oauth/token but it doesn't enter my MyFilter.
What am I suppose to do to call MyFilter after oauth/token call ?
You want to set cookie from authorization server or from resource server?
Is your auth server and resource server both are in same context? or different applications.?
I have two microservices. First one is authorization server, that provides jwt tokens (signed by its private key). Second microservice is a resource server, that validates tokens based on authorization server public key (exposed via REST endpoint by Auth server)
Do you want to set after receiving access_token from authorization server? What > do you want to do by setting cookie?
No. I would like the authorization server to set a cookie when oauth/token call is made by the frontend application. That way the browser is responsible for adding a token to each request rather than my frontend app. That protects me against XSS attack, as the cookie will be set as httpOnly and secure.
Is your plan is to read cookie for getting access_token?
Correct. But that supposed to be done by resource server (haven't done that, yet)
simple way is to create an API for the same functionality. Which takes access_token as request parameter and sets the cookie.
Are you suggesting something like a proxy microservice that stands between frontend application and auth/resource servers ? proxy microservice that is setting jwt token as cookie, and read token from cookie ?
No. I would like the authorization server to set a cookie when oauth/token call is made by the frontend application.
You need to add filter before all filters i mean filter order 1 so that request first reaches and last dispatches.
If it was not spring-boot it was much easier with web.xml or java config way of spring configuration. As spring boot does not rely on web.xml all filters are proxy filters except DelegatingFilterProxy(springSecurityFilterChain) before this we can not add any filters.
Possible way of achieving your requirement is registering a filter in FilterRegistrationBean with order(1).
Give the filter url pattern/oauth/token
In your filter use HttpServletResponseWrapper implementation to read response and get access_token and set cookie as per your requirement.
In Any configuration class register filter into FilterRegistrationBean
#Configuration
public class AppInitializer
{
#Bean
public FilterRegistrationBean<AccessTokenAlterFilter> sessionTimeoutFilter()
{
FilterRegistrationBean<AccessTokenAlterFilter> registrationBean = new FilterRegistrationBean<>();
AccessTokenAlterFilter filter = new AccessTokenAlterFilter();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns("/oauth/token");
registrationBean.setOrder(1); // set precedence
return registrationBean;
}
}
Your Filter
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccessTokenAlterFilter implements Filter
{
Logger OUT = LoggerFactory.getLogger(AccessTokenAlterFilter.class);
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
OUT.info("[[[[[[[[[[[[STARTED]]]]]]]]]]]]]]");
CharResponseWrapper wrappedResponse = new CharResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, wrappedResponse);
byte[] bytes = wrappedResponse.getByteArray();
String out = new String(bytes);
OUT.info("Response String: {}", out);
response.getOutputStream().write(out.getBytes());
OUT.info("[[[[[[[[[[[[ENDED]]]]]]]]]]]]]]");
}
private static class ByteArrayServletStream extends ServletOutputStream
{
ByteArrayOutputStream baos;
ByteArrayServletStream(ByteArrayOutputStream baos)
{
this.baos = baos;
}
public void write(int param) throws IOException
{
baos.write(param);
}
#Override
public boolean isReady()
{
return false;
}
#Override
public void setWriteListener(WriteListener listener)
{}
}
private static class ByteArrayPrintWriter
{
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
private PrintWriter pw = new PrintWriter(baos);
private ServletOutputStream sos = new ByteArrayServletStream(baos);
public PrintWriter getWriter()
{
return pw;
}
public ServletOutputStream getStream()
{
return sos;
}
byte[] toByteArray()
{
return baos.toByteArray();
}
}
public class CharResponseWrapper extends HttpServletResponseWrapper
{
private ByteArrayPrintWriter output;
private boolean usingWriter;
public CharResponseWrapper(HttpServletResponse response)
{
super(response);
usingWriter = false;
output = new ByteArrayPrintWriter();
}
public byte[] getByteArray()
{
return output.toByteArray();
}
#Override
public ServletOutputStream getOutputStream() throws IOException
{
if (usingWriter)
{
super.getOutputStream();
}
usingWriter = true;
return output.getStream();
}
#Override
public PrintWriter getWriter() throws IOException
{
if (usingWriter)
{
super.getWriter();
}
usingWriter = true;
return output.getWriter();
}
public String toString()
{
return output.toString();
}
}
}
Previous flow will be still there as given below
You can get response object under control and add the cookie. Just showing logs for your reference.

JAX-RS Injecting CDI Event in a class which implements ContainerRequestFilter

I'm trying to build a JAX-RS Rest API with Jersey. I'm following the most up-voted answer from this thread: Best practice for REST token-based authentication with JAX-RS and Jersey
I got to the Identifying the current user part. I'm trying to use CDI.
Here is my main app class:
public class Main {
// Base URI the Grizzly HTTP server will listen on
public static final String BASE_URI = "http://localhost:8080/myapp/";
/**
* Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
* #return Grizzly HTTP server.
*/
public static HttpServer startServer() {
// create a resource config that scans for JAX-RS resources and providers
// in appServer package
final ResourceConfig rc = new ResourceConfig().packages("appServer");
rc.register(new CORSFilter());
rc.register(new AuthenticationFilter());
// 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, false);
}
/**
* Main method.
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
final Weld weld = new Weld();
weld.initialize();
final HttpServer server = startServer();
server.start();
new SessionUtil().buildSession(args);
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
weld.shutdown();
}
}
And the relevant filter class:
import appServer.AuthenticatedUser;
import appServer.Secured;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import javax.annotation.Priority;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Event;
import javax.enterprise.inject.Default;
import javax.inject.Inject;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
#Secured
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
private static final String REALM = "myRealm";
private static final String AUTHENTICATION_SCHEME = "Bearer";
public AuthenticationFilter() {
super();
}
#Inject
#AuthenticatedUser
Event<String> userAuthenticatedEvent;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the Authorization header from the request
String authorizationHeader =
requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// Validate the Authorization header
if (!isTokenBasedAuthentication(authorizationHeader)) {
abortWithUnauthorized(requestContext);
return;
}
// Extract the token from the Authorization header
String token = authorizationHeader
.substring(AUTHENTICATION_SCHEME.length()).trim();
try {
// Validate the token
validateToken(token);
// if successful, fire event with token
userAuthenticatedEvent.fire(token);
} catch (Exception e) {
abortWithUnauthorized(requestContext);
}
}
private boolean isTokenBasedAuthentication(String authorizationHeader) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
// The authentication scheme comparison must be case-insensitive
return authorizationHeader != null && authorizationHeader.toLowerCase()
.startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " ");
}
private void abortWithUnauthorized(ContainerRequestContext requestContext) {
// Abort the filter chain with a 401 status code response
// The WWW-Authenticate header is sent along with the response
requestContext.abortWith(
Response.status(Response.Status.UNAUTHORIZED)
.header(HttpHeaders.WWW_AUTHENTICATE,
AUTHENTICATION_SCHEME + " realm=\"" + REALM + "\"")
.build());
}
private void validateToken(String token) throws Exception {
// Check if the token was issued by the server and if it's not expired
// Throw an Exception if the token is invalid
}
When I run the application it crashes with this error:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no
object available for injection at
SystemInjecteeImpl(requiredType=Event,parent=AuthenticationFilter,qualifiers={#javax.enterprise.inject.Default(),#appServer.AuthenticatedUser()},position=-1,optional=false,self=false,unqualified=null,997918120)
I have came across this question: How to use CDI Events in Java Jersey? but there was no relevant answer.
I have tried other solutions posted for similar problems but none of them worked.
So, it is obviously some sort of injection issue here:
#AuthenticatedUser
#Inject
Event<String> userAuthenticatedEvent;
Or maybe I'm not registering the Filter properly.
Any suggestions ?

Javax WebSockets won't work with programmattic Tomcat 7 instantiation

Here's what I'm trying to do:
Set up a Tomcat 7 server programmatically - that works with a simple servlet. I'm defining Tomcat's endpoints from within the code only, there are no settings nor routers on the file system (this is a constraint).
Have the said Tomcat server include a websocket server endpoint using Javax Websockets API (1.1) - that doesn't work.
My app/server entry point:
package com.myapp;
import java.io.File;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.deploy.FilterDef;
import org.apache.catalina.deploy.FilterMap;
import org.apache.catalina.startup.Tomcat;
public class App
{
public static void main(String[] args) throws LifecycleException
{
int port = 8080;
Tomcat webServer = new Tomcat();
webServer.setPort(port);
webServer.setHostname("localhost");
String appBase = ".";
webServer.getHost().setAppBase(appBase);
File docBase = new File(System.getProperty("java.io.tmpdir"));
Context context = webServer.addContext("", docBase.getAbsolutePath());
// both MyServlet and MyFilter exist and work.
Class servletClass = MyServlet.class;
Tomcat.addServlet(context, servletClass.getSimpleName(), servletClass.getName());
context.addServletMapping("/my-servlet/*", servletClass.getSimpleName());
Class filterClass = MyFilter.class;
FilterDef myFilterDef = new FilterDef();
myFilterDef.setFilterClass(filterClass.getName());
myFilterDef.setFilterName(filterClass.getSimpleName());
context.addFilterDef(myFilterDef);
FilterMap myFilterMap = new FilterMap();
myFilterMap.setFilterName(filterClass.getSimpleName());
myFilterMap.addURLPattern("/my-servlet/*");
context.addFilterMap(myFilterMap);
webServer.start();
webServer.getServer().await();
}
}
My websocket server endpoint class:
package com.myapp;
import java.nio.ByteBuffer;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/web-socket/")
public class WebSocket
{
#OnOpen
public void onOpen()
{
System.out.println("Open Connection ...");
}
#OnMessage
public static void onTextMessage(Session session, String msg) {
System.out.println("On Message for Web Socket");
}
#OnMessage
public void onBinaryMessage(Session session, ByteBuffer msg){
System.out.println("On Message for Web Socket");
}
#OnMessage
public void onPongMessage(Session session, PongMessage pMsg) {
System.out.println("On Message for Web Socket");
}
#OnClose
public void onClose(Session session) {
System.out.println("Connection Close for Web Socket");
}
#OnError
public void onError(Throwable e)
{
e.printStackTrace();
}
}
I'm using Maven, and I'm including the WebSocket API with <scope>provided</scope>, as I've seen in other questions that this was the root of other problems.
When I run the server, I can hit the my-servlet endpoint successfully (as a web page, of course), but when I try to create a WS object, simply within the browser's dev console using var webSocket = new WebSocket("ws://localhost:8080/web-socket"), it says that it can't hit the endpoint:
WebSocket connection to 'ws://localhost:8080/web-socket' failed: Error during WebSocket handshake: Unexpected response code: 404
My question: What am I missing? The error message (from Chrome) suggests that the endpoint isn't registered (hence the 404). How do I register the websocket ServerEndpoint? Thanks!
EDIT:
Here's my implementation of MyServlet class:
package com.myapp;
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet
{
#Override
protected void doGet(
HttpServletRequest req,
HttpServletResponse resp) throws IOException
{
resp.setStatus(HttpServletResponse.SC_OK);
resp.getWriter().write("Works...");
resp.getWriter().flush();
resp.getWriter().close();
}
}
And here's my implementation of MyFilter:
package com.myapp;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class MyFilter implements Filter
{
#Override
public void init(FilterConfig filterConfig)
{
// ...
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.addHeader("myHeader", "myHeaderValue");
chain.doFilter(request, httpResponse);
}
#Override
public void destroy()
{
// ...
}
}
Try this to manually add web socket endpoint:
String serverContainerClass = ServerContainer.class.getName();
//should be "javax.websocket.server.ServerContainer", if not, some external package could have hogged the implementation
final ServerContainer serverContainer = (ServerContainer) context.getServletContext().getAttribute(serverContainerClass);
try
{
serverContainer.addEndpoint(WebSocket.class);
}
catch (DeploymentException e)
{
TraceWriter.Error(this, "Failed to initialize websocket", e);
}
You should put this code after you add servlet to context

Test Spring-Rest Service with embedded Jetty

i want to create an embedded jetty server (not maven, gradle etc.) to test a spring rest service.
Therefor i created an EmbeddedServer class. But unfortunately invocation of the rest service leads always to an http 404 error. What doing wrong?
The rest service works fine with tomcat (not embedded).
Im using the following dependencies:
"org.eclipse.jetty:jetty-server:8.1.17.v20150415"
"org.eclipse.jetty:jetty-webapp:8.1.17.v20150415"
Here is the EmbededServer class:
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
public class EmbeddedServer {
private Server server;
public void start() throws Exception {
this.server = createServer();
this.server.start();
}
public void stop() throws Exception {
this.server.stop();
this.server.join();
this.server.destroy();
}
private Server createServer() {
final Server server = new Server(8080);
final WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setResourceBase("src/main/webapp");
context.setDescriptor("src/main/webapp/WEB-INF/web.xml");
context.setParentLoaderPriority(true);
context.setServer(server);
server.setHandler(context);
return server;
}
}
And the test class:
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
public class SimpleTest {
private HttpClient client;
private EmbeddedServer server;
#Before
public void before() throws Exception {
this.client = new DefaultHttpClient();
this.server = new EmbeddedServer();
this.server.start();
}
#After
public void after() throws Exception {
this.server.stop();
}
#Test
public void invokeHello() throws Exception {
final HttpResponse response = invokeGetRequest("http://localhost:8080/hello");
verifyResponse(response, 200, "hello");
}
private HttpResponse invokeGetRequest(final String path) throws Exception {
final URI wsAddress = new URI(path);
final HttpGet method = new HttpGet(wsAddress);
return this.client.execute(method);
}
private void verifyResponse(final HttpResponse actualHttpResponse, final int expectedHttpCode, final String expectedResponse) throws IOException {
assertThat(actualHttpResponse.getStatusLine().getStatusCode(), equalTo(expectedHttpCode));
final String actualResponse = EntityUtils.toString(actualHttpResponse.getEntity(), "UTF-8");
assertThat(actualResponse, equalTo(expectedResponse));
}
}
This test fails with:
java.lang.AssertionError:
Expected: <200>
but: was <404>
Path of ResourceBase and Descriptor must be absolute.
context.setResourceBase("c:/myapp/src/main/webapp");
context.setDescriptor("c:/myapp/src/main/webapp/WEB-INF/web.xml");

Categories