I'm using a very simple httpServer in Java for an api rest with GET, POST, PUT and DELETE. I'm using Basic Authentication and I have a couple classes Authentication.java and Authorisation.java which I use to authenticate and check permissions for the users.
So, the thing is that I want all users (authenticated) to be able to GET information from my api rest, but only users with certain privileges to be able to POST, PUT and DELETE. So how can I do that?
This is what I got
public class Server {
private static HttpServer server;
public static void start() throws IOException {
server = HttpServer.create(new InetSocketAddress(8000), 0);
HttpContext ctx = server.createContext("/users", new UserHandler());
ctx.setAuthenticator(new ApiRestBasicAuthentication("users"));
server.start();
}
}
And this is my ApiRestBasicAuthentication
public class ApiRestBasicAuthentication extends BasicAuthenticator {
private UserAuthentication authentication = new UserAuthentication();
public ApiRestBasicAuthentication(String realm) {
super(realm);
}
@Override
public boolean checkCredentials(String user, String pwd) {
int authCode = authentication.authenticate(user, pwd);
return authCode == UserAuthentication.USER_AUTHENTICATED;
}
}
As this is now, check credentials is only checking if the user is authenticated. But I'd like to check, if the method is POST, DELETE or PUT I should also check the specific credentials. But how can I get the method in my ApiRestBasicAuthentication? I'm doing that in my handler class
public void handle(HttpExchange httpExchange) throws IOException {
String method = httpExchange.getRequestMethod();
if ("post".equalsIgnoreCase(method)) {
createUser(httpExchange);
} else if ("get".equalsIgnoreCase(method)) {
readUsers(httpExchange);
} else if ("put".equalsIgnoreCase(method)) {
updateUser(httpExchange);
} else if ("delete".equalsIgnoreCase(method)) {
deleteUser(httpExchange);
}
}
Maybe this is supposed to be done some other way. Any ideas?
Many thanks.
A simple way to do it would be to change your ApiRestBasicAuthentication like:
public class ApiRestBasicAuthentication extends BasicAuthenticator {
private UserAuthentication authentication = new UserAuthentication();
public ApiRestBasicAuthentication(String realm) {
super(realm);
}
@Override
public Authenticator.Result authenticate(HttpExchange exch) {
Authenticator.Result result=super.authenticate(exch);
if(result instanceof Authenticator.Success) {
HttpPrincipal principal=((Authenticator.Success)result).getPrincipal();
String requestMethod=exch.getRequestMethod();
if( ADD SOME LOGIC HERE FOR PRINCIPAL AND REQUEST METHOD) {
return new return new Authenticator.Failure(401);
}
return result;
}
}
@Override
public boolean checkCredentials(String user, String pwd) {
int authCode = authentication.authenticate(user, pwd);
return authCode == UserAuthentication.USER_AUTHENTICATED;
}
}
And add some logic there for requests/users that you want to fail the authenticator. I have shown you here how to get the method in the authenticate method but you need to specify the types of credentials.
Another solution would be if you check the source code of BasicAuthenticator you can see how it implements authenticate
method and you can create your own implementation in a similar way instead of extending BasicAuthenticator and use the get method instead of just the username and password. You can see the source code here and I am sure you will be able to find your way around ;)
Usually in enterprise application you can use some external security management system - for example if you use Spring (the de facto standard in the current java web apps) you can use spring security and do such security patterns and filters in a more declarative way
While the above answers might be valid for you, I think you should also consider using defined roles and security-constraints which can be defined in your web.xml and used in the REST Resource using @RolesAllowed annotation. This then allows you to specifically allow permissions for methods individually or at the REST resource/class level.
In web.xml, this looks something like this:-
<security-role>
<role-name>SERVERTOSERVER</role-name>
</security-role>
<security-constraint>
<web-resource-collection>
<web-resource-name>REST API description</web-resource-name>
<url-pattern>/<path name>/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<description>Only allow users
from following roles</description>
<role-name>SERVERTOSERVER</role-name>
</auth-constraint>
</security-constraint>
The following links have some examples: Purpose of roles tags in tomcat-users.xml? , https://www.thecoderscorner.com/team-blog/hosting-servers/17-setting-up-role-based-security-in-tomcat/
In case helpful, here is another type of solution for a Jersey based application: https://howtodoinjava.com/jersey/jersey-rest-security/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With