JAVA Spring Custom Authentication Using MongoDB for fetching stored user credentials - spring-boot

Hi Stackoverflow team,
I am facing an issue in my REST Call which I am clueless about after trying to dig into the HTTP errors.
Somehow the authorization isn't working , eventhough the generation and fetch of the JWT token is successful.
Short Description of what I have in my Springboot App :
(Available for analysis of the problem at)
https://github.com/vivdso/SpringAuthentication
A DbRepository call that talks to a backend MongoDb collection named UserAccounts which has roles and credential details stored including the passwords (Ciphertexts).
A JWT token generation mechanism that returns a token which has to be attached to the HTTP Headers for the subsequent API Calls.
The flow in short.
".....:8080/auth" method post Content-Type appliction/json body:{"username":"user","password":"sample"} Response should be a jwt token
and then
Try the autheticated url .....:8080/order.
****EXPECTED RESULT : Header" Authorization:{$jwtToken from step 6} Actual Result: :( Error : 403 forbidden, this should be fully authenticated and should let the user access this api. Expected Result: "Hello here is my order"****
This is just a simple application with not too many details to worry about.
Any help will be appreciated.
Thanks in advance.

in your code I couldn't find the filter registration.
Try to add it in the WebSecurityConfig.java
#Bean
public CustomAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
CustomAuthenticationTokenFilter authenticationTokenFilter = new CustomAuthenticationTokenFilter ();
authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationTokenFilter;
}
and then register it with
http
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
inside the configuration method
et me know

This was a role mismatch issue. Was not matching with the role in jwt.
Changed the code to correct the role and it worked fine -
public CustomDbRepository(){
List<String> roles = new ArrayList<>(1);
//roles.add("ROLE_USER");
roles.add("USER");

Related

oAuth2.0 - Fitbit does not return auth code (attributes cannot be empty error)

Ive been struggling with implementing the Authorization Code Grant flow for the Fitbit API. Ive set up the WebSecurityConfigurerAdapter, and I get correctly redirected to the Fitbit /oauth2/authorize page, where I can give permission. However, when I allow my application access, it says the following: authorization_request_not_found. Also, the url does not include a code.
I cannot really find good documentation on how to implement the next step using Spring Boot.
It would be greatly appreciated if anyone could point me in the right direction. Thanks
Stack:
The problem is in access token request. Following authorization code grant flow you need to set authorization header to basic. Your client_id and secret concatenated with a colon and encoded to Base64 will be your basic authorization header value.
You can find more info in official docs: Access Token Request
Implementing this in spring security is quite simple. Just follow this tutorial:
Custom Token Request
Convert method of CustomRequestEntityConverter class should look like this one below:
#Override
public RequestEntity<?> convert(OAuth2AuthorizationCodeGrantRequest req) {
RequestEntity<?> entity = defaultConverter.convert(req);
MultiValueMap<String, String> headers = entity.getHeaders();
String authorization = Base64.getEncoder().encodeToString(BASIC_AUTHORIZATION.getBytes());
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setBasicAuth(authorization);
httpHeaders.addAll(headers);
return new RequestEntity<>(entity.getBody(), httpHeaders, entity.getMethod(), entity.getUrl());
}

AuthenticationPrincipal is null only with Postman request

I am trying run below application in my local(with necessary config changes related to OKTA)
https://github.com/oktadeveloper/okta-spring-security-authentication-example/tree/master/oauth-okta
All is working fine when application is accessed by browser. authentication is working fine at OKTA and redirected to application correctly.
but when i tried the same API using postman, OidcUser is coming as null.
I generated accessToken from postman with grant_type client_credentials
#AuthenticationPrincipal OidcUser oidcUser
any clues?
-R
Here is the answer from another forum.
My guess is this is how Spring Security works. It will populate this parameter if you login with a browser, but not if you send an access token. You could use the access token to call the /userinfo endpoint and get the user’s information that way. Or you could use Jwt instead of OidcUser, like this example shows.
#GetMapping("/")
public String index(#AuthenticationPrincipal Jwt jwt) {
return String.format("Hello, %s!", jwt.getSubject());
}

How to use Restcall with Spring Security

In my Spring MVC application I am using spring security. It works fine so far, but I have to admit, I do not understand all the details.
In the same application the user can call some controller functions by rest api. When the user (lets say Tom) does this, his authentication is lost. Instead the controller is called by user anonymous.
I tracked down that "user switch" to the code below. Variable restCall contains an url to my application. That call would work for user Tom, if he would place it in the browser directly. Using the restcall, the user changes to anyonymous.
1) Can I prevent that, when the calling User (Tom) was already logged in?
2) As those services should be called by a user that is not already browsing the web interface of the application, I would have to find a way to login by the rest call itself.
private void callWebservice(HttpServletRequest req, String restCall) {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response
= restTemplate.getForEntity(restCall, String.class);
logger.debug(response.toString());
//assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
You need, for example, a JSON Web Token (JWT) Authentication.
Steps are the following:
1) Client does an authentication, a post request with username and password
2) If authentication is successful, server returns a token in which is coded the user
3) In your next call, GET or POST, you add JWT to your header, this way the server will know who you are, because server can decode the token, and can grant also the right authorities and functionalities

Spring Keycloak adapter Permissions Policy Enforcer. How to set it up

First of all I'm using
keycloak-authz-client-3.3.0.Final
spring boot 1.5.8.RELEASE
spring-boot-starter-security
I've been playing with Keycloak spring adapter exploring the examples since we want to adopt it to our project.
I was able to make it run for Roles easily using this tutorial:
https://dzone.com/articles/easily-secure-your-spring-boot-applications-with-k
After that I moved to permissions and that's when it gets trickier (that's also our main goal).
I want to achieve something like described in here (9.1.2):
http://www.keycloak.org/docs/2.4/authorization_services_guide/topics/enforcer/authorization-context.html#
To get permissions you need to setup in Keycloak Authorization, credentials, and then create Resources or Scopes and Policies to be able to create permissions (it took me a while but I got it working). Testing in the Evaluater everything seems fine.
Next step was to get user permissions on the Spring side. In order to do that I had to enable:
keycloak.policy-enforcer-config.enforcement-mode=permissive
The moment I enable this I get everytime this exception
java.lang.RuntimeException: Could not find resource.
at org.keycloak.authorization.client.resource.ProtectedResource.findAll(ProtectedResource.java:88)
at org.keycloak.adapters.authorization.PolicyEnforcer.configureAllPathsForResourceServer...
...
Caused by: org.keycloak.authorization.client.util.HttpResponseException:
Unexpected response from server: 403 / Forbidden
No matter what address I hit in the server.
So I started to investigate what was the root of the problem. Looking at some examples how to manually get the permissions I actually got them in postman with the following request:
http://localhost:8080/auth/realms/${myKeycloakRealm}/authz/entitlement/${MyKeycloakClient}
including the header Authorization : bearer ${accessToken}
response was {"rpt": ${jwt token}} that actually contains the permissions
So knowing this was working it must be something wrong with the Spring adapter. Investigating a bit further on the Keycloak exception I found that that error was occurring the moment the adapter was getting all the resources. For that it was using the following url:
http://localhost:28080/auth/realms/license/authz/protection/resource_set
with a different token in the headers (that I copied when debugging)
So when I tried it in postman I also got a 403 error, but with a json body:
{
"error": "invalid_scope",
"error_description": "Requires uma_protection scope."
}
I've enabled and disabled all uma configuration within keycloak and I can't make it work. Can please someone point me into the right direction?
Update
I've now updated Keycloak adapter to 3.4.0.final and I'm getting the following error in the UI:
Mon Nov 20 10:09:21 GMT 2017
There was an unexpected error (type=Internal Server Error, status=500).
Could not find resource. Server message: {"error":"invalid_scope","error_description":"Requires uma_protection scope."}
(Pretty much the same I was getting in the postman request)
I've also printed all the user roles to make sure the uma_protection role is there, and it is.
Another thing I did was to disable spring security role prefix to make sure it wasn't a mismatch on the role.
Update 2
Was able to resolve the 403 issue (you can see it in the response below).
Still getting problems obtaining KeycloakSecurityContext from the HttpServletRequest
Update 3
Was able to get KeycloakSecurityContext like this:
Principal principal = servletRequest.getUserPrincipal();
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) principal;
OidcKeycloakAccount auth = token.getAccount();
KeycloakSecurityContext keycloakSecurityContext = auth.getKeycloakSecurityContext();
AuthorizationContext authzContext = keycloakSecurityContext.getAuthorizationContext();
The problem now is that the AuthorizationContext is always null.
I've managed to get it working by adding uma_protection role to the Service Account Roles tab in Keycloak client configuration
More information about it here:
http://www.keycloak.org/docs/2.0/authorization_services_guide/topics/service/protection/whatis-obtain-pat.html
Second part of the solution:
It's mandatory to have the security constrains in place even if they don't mean much to you. Example:
keycloak.securityConstraints[0].authRoles[0] = ROLE1
keycloak.securityConstraints[0].securityCollections[0].name = protected
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /*
Useful demos:
https://github.com/keycloak/keycloak-quickstarts
This code works for me:
HttpServletRequest request = ...; // obtain javax.servlet.http.HttpServletRequest
Principal userPrincipal = request.getUserPrincipal();
KeycloakPrincipal < KeycloakSecurityContext > keycloakPrincipal =
(KeycloakPrincipal < KeycloakSecurityContext > ) userPrincipal;
KeycloakSecurityContext securityContext =
keycloakPrincipal.getKeycloakSecurityContext();
If you faced "java.lang.RuntimeException: Could not find resource" error and you are using Keycloak docker container, The error can be because of this. I dont have enough information about docker. Hence I download keycloak as a zip file and run it. It works properly.

Spring OAuth2: support auth and resource access with both SSO and custom auth server

I've found similar issue but it's unanswered, so I suppose I'm going to duplicate question a little.
I am using Spring OAuth2 to implement separate resource and custom authentification servers.
I've already configured interaction with auth server through issuing&validating JWT tokens and everything seems fine.
Now I'm trying to add SSO functionality but really stuck with it. I've researched the official Spring examples and attached guide but it is very short worded when it comes to connecting SSO part with custom server authentication. And actually author uses only external provider resource ('user' info) to show process.
I think it is normal thing to have all this SSO means of authentication and also custom registration. I can see it works well with stackoverflow for example.
I am loking for directions where to find any info about handling on resource server different kind of tokens issued by multiply SSO providers and also from custom auth server.
Maybe I can use auth chain to do this and some mean to distinguish token format to know how to process it. Is it possible with Spring OAuth2? Or I need to do this magic somehow manually?
For now I have just one 'maybe strange' idea:
To not involve my own resource server with this SSO stuff at all. After receiving Facebook (for example) token - just exchange it for api JWT token with custom auth server (associating or creating user on the way) and then work with resource server on standard basics
EDITED:
I've found at least something. I've read about configuring filters in authorization chain and translate given social tokens to my custom JWT-s as 'post authenticate'(not a crazy idea after all). But it mostly done with SpringSocial.
So now question is: how to do that?
Forgot to say that I am using Password Grant for authentication on custom server. Clients will be only trusted application and I do not even sure about browser client (thinking about only native mobile options). Even if I decide to have browser client I'll make sure it's going to have backend to store sencetive information
Ok, so after struggling to implement such behavior I've stuck with two different libraries (Spring Social & OAuth2). I decided to go my own way and do it with just Spring OAuth2:
I have the resource server, authentication server and client(backed up by Java and uses OAuth2 Client library, but it can be any other client) - my resources can be consumed only with my own JWT auth token given by my own auth server
in a case of a custom registration: client obtains JWT token(with refresh token) from auth server and sends it to the res server. Res server validates it with public key and gives the resource back
in a case of SSO: client obtains Facebook(or other social platform token) and exchanges it for my custom JWT token with my custom auth server. I've implemented this on my auth server using custom SocialTokenGranter(currently handles facebook social token only. For every social network I'll need separate grant type). This class makes an additional call to facebook auth server to validate token and obtain user info. Then it retrieves the social user from my db or creates new and returns JWT token back to the client. No user merging is done by now. it is out of scope for now.
public class SocialTokenGranter extends AbstractTokenGranter {
private static final String GRANT_TYPE = "facebook_social";
GiraffeUserDetailsService giraffeUserDetailsService; // custom UserDetails service
SocialTokenGranter(
GiraffeUserDetailsService giraffeUserDetailsService,
AuthorizationServerTokenServices tokenServices,
OAuth2RequestFactory defaultOauth2RequestFactory,
ClientDetailsService clientDetailsService) {
super(tokenServices, clientDetailsService, defaultOauth2RequestFactory, GRANT_TYPE);
this.giraffeUserDetailsService = giraffeUserDetailsService;
}
#Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails clientDetails, TokenRequest request) {
// retrieve social token sent by the client
Map<String, String> parameters = request.getRequestParameters();
String socialToken = parameters.get("social_token");
//validate social token and receive user information from external authentication server
String url = "https://graph.facebook.com/me?access_token=" + socialToken;
Authentication userAuth = null;
try {
ResponseEntity<FacebookUserInformation> response = new RestTemplate().getForEntity(url, FacebookUserInformation.class);
if (response.getStatusCode().is4xxClientError()) throw new GiraffeException.InvalidOrExpiredSocialToken();
FacebookUserInformation userInformation = response.getBody();
GiraffeUserDetails giraffeSocialUserDetails = giraffeUserDetailsService.loadOrCreateSocialUser(userInformation.getId(), userInformation.getEmail(), User.SocialProvider.FACEBOOK);
userAuth = new UsernamePasswordAuthenticationToken(giraffeSocialUserDetails, "N/A", giraffeSocialUserDetails.getAuthorities());
} catch (GiraffeException.InvalidOrExpiredSocialToken | GiraffeException.UnableToValidateSocialUserInformation e) {
// log the stacktrace
}
return new OAuth2Authentication(request.createOAuth2Request(clientDetails), userAuth);
}
private static class FacebookUserInformation {
private String id;
private String email;
// getters, setters, constructor
}
}
And from class extending AuthorizationServerConfigurerAdapter:
private TokenGranter tokenGranter(AuthorizationServerEndpointsConfigurer endpoints) {
List<TokenGranter> granters = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
granters.add(new SocialTokenGranter(giraffeUserDetailsService, endpoints.getTokenServices(), endpoints.getOAuth2RequestFactory(), endpoints.getClientDetailsService()));
return new CompositeTokenGranter(granters);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
...
.allowFormAuthenticationForClients() // to allow sending parameters as form fields
...
}
Every JWT token request is going to 'host:port + /oauth/token' url
Depending on 'Grant type' the server will handle such requests differently. Currently I have 'password'(default), 'refresh_token' and 'facebook_social'(custom) grant types
For default 'password' Grant type the client should send next parameters:
clientId
clientSecret (depends of the client type. Not for single-page clients)
username
password
scope (if not explicitly set in auth server configuration for current client)
grantType
For 'refresh_token' Grant type the client should send next parameters:
clientId
clientSecret (depends of the client type. Not for single-page clients)
refresh_token
grantType
For 'facebook_social' Grant type the client should send next parameters:
clientId
facebook_social_token (custom field)
grantType
Based on the client design the way to send these requests will be different.
In my case with test Java based client which uses Spring OAuth2 library to obtain the social token I do the token exchange procedure with the redirect in controller(controller being invoked using url defined in facebook dev page configuration).
It can be handled in two stages: after obtaining facebook social token JavaScript can make a separate explicit call to my auth server to exchange tokens.
You can see Java client implementation examples here, but I doubt that you're going to use Java client in production:https://spring.io/guides/tutorials/spring-boot-oauth2/

Resources