Implementing Authentication for a WebDAV Servlet - java

I am currently using this WebDAV Java Servlet Implementation, it's as far as I know the smallest and the easiest to use WebDAV java solution that doesn't depend on Tomcat ( Using WebLogic ).
So I would like to extend this to use my underlying security layer which somewhat uses a database connection to authenticate users.
My question is if this is possible? Does the HttpServletRequest even get the Authentication?
Consider the following method header:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { }
Now I would like to use req.getPrincipal to get the User Principal containing the Username and Password. However, my getPrincipal always returns null even if I set my WebDAV client to Windows Authentication or anything else for that matter.

If you are using your own authentication layer, you need to inject your authentication information to the ServletRequest. This is normally done through a filter and wrapped HttpServletRequest.
You can find a good example in CAS,
http://www.jasig.org/cas
Download the source and look at this class,
org.jasig.cas.client.web.filter.HttpServletRequestWrapperFilter

Related

Sending information from a servlet back to a Filter

I have an old web application, running on Tomcat 7, that uses a very rudimentary open-session-in-view mechanism provided by a filter:
#Override public void doFilter (ServletRequest req, ServletResponse resp, FilterChain fc)
throws IOException, ServletException
{
try {
HibernateUtil.beginTransaction();
fc.doFilter(req, resp);
HibernateUtil.commitTransaction();
} catch (Throwable t) {
Logger.exception(t, "processing servlet request");
HibernateUtil.rollbackTransaction();
throw new ServletException(t);
}
}
I'm stuck with this now, and I think I'm running into one of the many flaws with OSIV (or at least this implementation of it) which is that I now want to be able to rollback transactions even without an exception being thrown. I want servlets to be able to control that, and I don't think I have much choice except to hack this functionality on somehow.
My question is: How can I communicate some sort of "rollback" flag from an arbitrary servlet back up to this filter? I want to be able to do something like this in the filter:
HibernateUtil.beginTransaction();
fc.doFilter(req, resp);
if (/* something that was set by a servlet/jsp */)
HibernateUtil.rollbackTransaction();
else
HibernateUtil.commitTransaction();
I'm not really sure what a reliable way to propagate information like that from a servlet back out to this filter is.
I don't advise using request attributes or thread-local variables, which has the following issues:
Your transaction is dependent on someone else having set a flag. If you work for a bank, I really don't wanna be a customer there.
Resource leaking if you don't clean up thread-local storage.
You can't write multithreaded code without manually copying stuff between thread-local storage.
If using request attribute, you'll have to extract the value in a Servlet and pass all the way to your DAO, assuming you're using a common multi layered architecture.
Instead, you can simply get the current transaction from the Hibernate session object and ask it to rollback. Session.getTransaction().rollback(). Best, scrap that code or find the person who wrote it and ask for a refund.

Don't allow direct calls to Microservices. Only allow through API Gateway

Maybe this is a strange question (I'm new with Microservices). But I'm looking for some info on how proceed with this. Does not need to be Spring specific, but that's the framework I'm using at the moment.
Example:
Lets say we have two Microservices
a) http://myurlfortesting.com:8085/api/rest/serviceone
b) http://myurlfortesting.com:8090/api/rest/servicetwo
and we have setup Spring Zuul (acting as the API Gateway) with the following rules that forward the incoming calls:
/rest/one -> http://myurlfortesting.com:8085/api/rest/serviceone
/rest/two -> http://myurlfortesting.com:8090/api/rest/servicetwo
The question...
Is there a way to stop users from directly accessing the services mentioned in A and B (only allow the ones that come through the API Gateway)?
Can this be done with Springs Zuul (Acting as a API Gateway) by setting up some extra filters or do we set it up in Microservices endpoints?
Would even like to know if there is a way to not even processing the direct calls on the Microservices endpoints that don't come via the API Gateway.
Maybe this is solved with server specific rules and has nothing to do with Spring?
Many thanks,
/D
Assuming that you have a firewall in place, you could restrict inbound traffic to server to the ports that your Zuul endpoints are exposed on and disallow anyone from accessing the microservices' ports directly.
If you want to avoid going the firewall route, you could force the endpoints to check for a specific HTTP header or something that is set by Zuul prior to forwarding a request, but that would be hacky and easy to circumvent. Based on my past experiences, the "right" way would be to do this via a firewall. Your app should be responsible for dealing with requests. Your firewall should be responsible for deciding who can hit specific endpoints.
Generally, such kind of situation are handled by implementing proper OAuth server wherein only your API gateway will handle the token validation. Any direct call to microservice will not have proper token exchange and hence requests will be aborted.
In case, you have deployed your micro-services on any cloud then you can acheive this by exposing routes to only API gateway.
And yes, firewall blocking, IP whitelisting are some of the other ways in restricting the access to your microservices.
Use a reverse proxy. We use Nginx for the same purpose. Api gateways should always be deployed behind a load balancer in production scenarios to avoid the gateway being a single point of failure(If it is not a managed service like AWS API gateway). Also, the gateway and services are deployed within a VPC and not visible to the public.
Hey I finally find a solution to accept request just from the API Gateway by using microservices architecture, for that you can create a filter, and like Zuul act as a proxy, checking the header 'X-Forwarded-Host', if it doesn't match with the gateway service then return an Unauthorised exception.
public class CustomGatewayFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String proxyForwardedHostHeader = request.getHeader("X-Forwarded-Host");
if (proxyForwardedHostHeader == null || !proxyForwardedHostHeader.equals(GatewayConstant.getGatewayURL())) {
UnauthorisedException unauthorisedException = new UnauthorisedException("Unauthorized Access",
"Unauthorized Access, you should pass through the API gateway");
byte[] responseToSend = restResponseBytes(unauthorisedException.getErrorResponse());
((HttpServletResponse) response).setHeader("Content-Type", "application/json");
((HttpServletResponse) response).setStatus(401);
response.getOutputStream().write(responseToSend);
return;
}
chain.doFilter(request, response);
}
private byte[] restResponseBytes(ErrorResponse errorResponse) throws IOException {
String serialized = new ObjectMapper().writeValueAsString(errorResponse);
return serialized.getBytes();
}
}
do not forget to add your custom filter in SpringSecurity Configuration
.and().addFilterBefore(new CustomGatewayFilter(), ConcurrentSessionFilter.class);
The right way to do this with AWS API Gateway would be with the recently launched 'VPC Link' integration, which secures the connection between API Gateway and your backend inside your VPC.
https://aws.amazon.com/about-aws/whats-new/2017/11/amazon-api-gateway-supports-endpoint-integrations-with-private-vpcs/

How To Implement Rest Full Web Service with Auth Token using Spring Security 4.0.1.RELEASE

I am trying to design an API Manager with RESTful webservice. In Spring's new release, we can combine everything in Java code without using web.xml nor securityconfig.xml.
According to Authtoken concept, API manager should have authtoken and refresh token for user authentication.
Please, can anyone give me sample source code or guidance how to implement RESTfull webservice with Spring Security.
I need to know how all configurations are implement in Java code.
it should have Authtoken concept also.
This Tutorial Say correct way to do this.
http://www.beingjavaguys.com/2014/10/spring-security-oauth2-integration.html
But Spring Configuration are in Spring.xml file.
I need to put them in to Java level also.
The people at Stormpath have a quite a straightforward solution for achieving Oauth. Please take a look at Using Stormpath for API Authentication.
As a summary, your solution will look like this:
You will use the Stormpath Java SDK to easily delegate all your user-management needs.
When the user presses the login button, your front end will send the credentials securely to your backend-end through its REST API.
2.1. By the way, Stormpath greatly enhances all the possibilities here. Instead of having your own login page, you can completely delegate the login/register functionality to Stormpath via its IDSite, or you can also delegate it to the Servlet Plugin. Stormpath also supports Google, Facebook, LinkedIn and Github login.
Your backend will then try to authenticate the user against the Stormpath Backend and will return an access token as a result:
/** This code will throw an Exception if the authentication fails */
public void postOAuthToken(HttpServletRequest request, HttpServletResponse response) {
Application application = client.getResource(applicationRestUrl, Application.class);
//Getting the authentication result
AccessTokenResult result = (AccessTokenResult) application.authenticateApiRequest(request);
//Here you can get all the user data stored in Stormpath
Account account = accessTokenResult.getAccount();
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json");
//Return the Access Token
response.getWriter().print(token.toJson());
response.getWriter().flush();
}
Then, for every authenticated request, your backend will do:
/** This is your protected API */
public void sayHello(HttpServletRequest request, HttpServletResponse response) {
Application application = client.getResource(applicationRestUrl, Application.class);
OauthAuthenticationResult result = (OauthAuthenticationResult) application.authenticateOauthRequest(request).execute();
System.out.println(result.getApiKey());
System.out.println(result.getAccount());
//At this point the authorization was successful, you can now allow the actual operation to be executed
doSayHello();
}
All this will not need any special Spring Security configuration, this is plain Java code that you can run in any framework.
Please take a look here for more information.
Hope that helps!
Disclaimer, I am an active Stormpath contributor.

Remote EJB from HttpServlet

I want to call a remote EJB from a different EJB server. I've Remote EJB's deployed on OpenEJB ,then I will call them from Glassfish HTTPServlet. I know on local EJB i can do #EJB annotation but I want user to "authenticate" remote OpenEJB server from Glassfish servlet.
on OpenEJB:
//OpenEJB server at 192.168.10.12
public class AdminManager {
#RolesAllowed("admin")
public void test() {
System.out.println("Admin called this method");
}
}
Glassfish Servlet
//Glassfish servlet at 192.168.10.10
public class AdminManage extends HttpServlet {
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Properties p = new Properties();
p.put("java.naming.factory.initial", "org.apache.openejb.client.RemoteInitialContextFactory");
p.put("java.naming.provider.url", "ejbd://192.168.10.12:4201");
// user and pass optional
String userName = req.getSession().getAttribute("username");
String password = req.getSession().getAttribute("password");
p.put("java.naming.security.principal", userName );
p.put("java.naming.security.credentials", "password );
final InitialContext ctx = new InitialContext(p);
final AdminManagerRemote myBean = (MyBean) ctx.lookup("AdminManagerRemote");
try {
myBean.test();
} catch(Exception epx) {
resp.sendRedirect(resp.encodeRedirectURL("/login"));
}
}
}
Okay this seems a solution but this is not "good" solution for me.
Everytime authenticating to openejb sucks , like this;
String userName = req.getSession().getAttribute("username");
String password = req.getSession().getAttribute("password");
p.put("java.naming.security.principal", userName );
p.put("java.naming.security.credentials", "password );
And the code is not clean.
I want user to authenticate only once and call ejb methods.
Is there any better solution then this?
Can I combine Glassfish HTTP authentication with remote openEJB authentication?
I mean when user authenticates to Glassfish HTTP server , i want openEJB authenticate as well.
This is really making me mad. what solution is good to escape from spagetti codes?
Two ideas:
Authenticate to OpenEJB when the user logs into Glassfish, store the EJB stub in the user session and reuse it later. I fear you will need to implement some EJB 2.x inteface for the serialization of the stub (so-called handle) to work.
Implement a cache where you store the EJB stubs. If a stub for the given username/password is in the cache, reuse it, if not, authenticate. The cache is a static object, it could be created for instance with Guava's CacheBuilder. This violates the spec (you should not use static to share information between servlets), but since it's a cache, it's not a big deal. It would even work in a cluster.
You can try introducing Service Locator Pattern to eliminate the redundancy in the code & hide the underlying details & complexity of creating initial context, JNDI lookup etc.
You can cache remote home interface EJBHome & then re-use it later when required.
Can refer Core J2EE Patterns - Service Locator documentation for more details.
What about Kerberos ? Someone know kerberos solution ?
Login to all remote servers with TGS.
But there is no sample for that on internet.
And its so evil hard to install kerberos with openldap.

How should I pass subject/principals/roles between application layers in Java?

I currently have a number of web applications which access a common service running in JBoss 5.0. The service is very simple, using Guice and POJOs. The web applications are authenticated and know who the user is and what roles they have. When calling the service how should I pass this authentication information to the service?
It would seem the simple approach is to simply add a parameter to the interface to take the user information. Possibly a Subject. But this has the downside of cluttering up the interface with contextual information that isn't specific to the job in hand.
void doSomething(Subject subject, ...) {
}
The alternative I have seen is to use ThreadLocal storage, put the user information in there before making the call and make this accessible via some utility class that the service can use. This cleans up the interface but hides the fact that the client of the service has to set the user information before making the call.
Is there another way of doing this? I get the feeling the AOP may be of use here too but can't quite see how. Is there some "best practice" I am missing? Would EJB help?
This cleans up the interface but hides the fact that the client of the
service has to set the user information before making the call.
True, but if you need to pass something to a particular method across the application then you are defeating the purpose of using Dependency Injection. It's there so that you don't have to pass a bunch of services and objects to other services and objects and so forth, they are created with everything they need.
Is there another way of doing this? I get the feeling the AOP may be
of use here too but can't quite see how. Is there some "best practice"
I am missing? Would EJB help?
The other way of doing this would be to use a single filter on every Servlet that calls the services that need the Subject / User. Set the user in the filter, and clear the user at the end in a try-finally block. In fact, OWASP Esapi uses this style when setting their ThreadLocalUser, it allows the User to be available in every part of the application.
Something like this:
#Singleton
public MyUserFilter extends FilterOfTheMonth {
private final Provider<Authenticator> authProvider;
#Inject
MyUserFilter(Provider<Authenticator> auth) {
this.authProvider = auth;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws java.io.IOException, ServletException {
try {
// Authenticate and SET the current user utilizing the request and/or
// session objects
authProvider.get().authenticateUser(HttpRequest currentRequest);
// Continue on here along the servlet chain
... other processing
} finally {
authProvider.get().getRidOfCurrentUser();
}
}
}
Have you considered moving the authentication process to the common service? Then you only need the session ID in the common service to identify all information about the user the request is coming from.

Categories

Resources