I am starting an application that uses a REST api which makes calls to an EJB layer on JBoss Wildfly (RestEasy).
The REST services are inside a war which then calls the ejb layer.
I know how to achieve BASIC or any custom form of authenthication on REST with an RestEasy Interceptor that checks Headers etc.
Basically like described here: http://howtodoinjava.com/2013/06/26/jax-rs-resteasy-basic-authentication-and-authorization-tutorial/
The problem now is - this is just a check on the REST facade. Inside the EJB layer I don't know the user that authenticated against the REST service.
To clear this - when using RMI and Remote EJB calls with authentication, the user name is stored in Session Context:
#Stateless
public class LoginService {
#Resource
private SessionContext sessionContext;
public String getCurrentUser() {
Principal principal = sessionContext.getCallerPrincipal();
return principal.getName(); //I need this to be the username from REST auth
//Currently it's anonymous
}
}
Is there a way to propagate the username in some standard way? E.g. putting a custom principal to SessionContext?
You can use the Subject's doAs method.
See the JavaDocs here.
When makings calls from the war to the EJB do it with the authenticated subject's doAs method. This way the subject is propagated to the context of the ejb. (eg. #RolesAllowed will work fine)
You can config the authentication in the web.xml as usual if you want.
To get the subject in the war, try this Subject userSubject=(Subject)PolicyContext.getContext("javax.security.auth.Subject.container");
Related
I'm trying to get logged in users' details who are connected via websocket on Spring Boot 2. To do this, I'm currently using SimpUserRegistry to find a list of connected SimpUsers.
Since Spring Boot 2.4, I noticed the SimpUser class has a getPrincipal() method that returns a generic Principal object. As each user is supposed to login via Spring Security's mechanisms, I thought I was able to cast it to Spring Security's UserDetails to get the logged in user , but I realize it wasn't the case.
Does anyone know how I can make use of getPrincipal or other ways to get logged in userDetails?
First of all, let's make it clear that, to use getPrincipal() with websocket, you have to implement websocket authentication and authorization through Interceptor (as far as I know SpringSecurity doesn't do this automatically).
After doing the above correctly, you can now use the getPrincipal () method. It will return The identity of the principal being authenticated (maybe Username, email,...)
You can use code that looks like this:
#MessageMapping("/test")
public void doSomething(#Payload AppMessage appMessage, Principal principal) {
String username = principal.getName();
// find userDetail with username here
}
I need to get access token (grant_type = client_credentials) in the service layer of my spring boot application to talk to other microservice (service to service interaction). There is no spring http session or auth at this layer, I just have client_id, client_secret and token url. These properties are set in application.properties as:
spring.security.oauth2.client.registration.auth1.client-id=***
spring.security.oauth2.client.registration.auth1.client-secret=***
spring.security.oauth2.client.registration.auth1.authorization-grant-type=client_credentials
spring.security.oauth2.client.provider.auth1.tokenUri=***
This seemed simple with Spring Security OAuth, but can't figure out with Spring security. Referred the documents for spring security 5, but everything seems to be in context of web interface. I understand I could just make http call to get the token with the info I have, but I wanted to utilize the framework...
Scenario:
Lets call this spring boot app service A. There are other services which might call A to process updates on http or send kafka message on a topic which A listens to. When A processes the update/message, it needs to send some data to service B which requires access token for authz. This is where I need the access token. So the interaction is essentially service-service and is not specific to user.
When not in the context of a web interface, you'll want to look at the service layer.
From Spring Security's Javadocs for AuthorizedClientServiceOAuth2AuthorizedClientManager:
An implementation of an {#link OAuth2AuthorizedClientManager} that is capable of operating outside of a {#code HttpServletRequest} context, e.g. in a scheduled/background thread and/or in the service-tier.
Here's a #Bean definition that may help, which I'll explain below:
#Bean
OAuth2AuthorizedClientManager authorizedClientManager
(ClientRegistrationRepository clients) {
OAuth2AuthorizedClientService service =
new InMemoryOAuth2AuthorizedClientService(clients);
AuthorizedClientServiceOAuth2AuthorizedClientManager manager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(clients, service);
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
manager.setAuthorizedClientProvider(authorizedClientProvider);
return manager;
}
An OAuth2AuthorizedClientManager manages authorizing OAuth 2.0 client definitions. These definitions are stored in a ClientRegistrationRepository, and a default instance of ClientRegistrationRepository is created by Spring Boot via the properties you've already got defined.
The manager typically needs two things to function:
The first is an OAuth2AuthorizedClientService, which is handy if you are wanting to store tokens in a database - in Spring Security 5.2, the only implementation is an in-memory one; however, it appears that 5.3 will ship with a JDBC implementation.
The second is an OAuth2AuthorizedClientProvider, which is what actually performs the token requests, like the client credentials one you want to make.
With this manager created, you can wire it into your web client:
#Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
new ServletOAuth2AuthorizedClientExchangeFilterFunction
(authorizedClientManager);
oauth2.setDefaultClientRegistrationId("auth1");
return WebClient.builder()
.apply(oauth2.oauth2Configuration())
.build();
}
The exchange filter function used above is the thing that adds the bearer token to the Authorization header. It calls the manager to ask it for a token, the manager pulls it from the service. If it's expired, the manager asks the provider to refresh it. Now, with a fresh token, the manager hands it back to the filter to get it added into the request.
I'm using roles authorization in my application as below,
**#RolesAllowed("Admin")**
public class ExampleResource {
//
#GET
#Produces(MediaType.APPLICATION_JSON)
**#RolesAllowed({"Admin", "User"})**
public Response getUsers(){
}
}
The authorization is working fine when login as "Admin/User". Similarly I applied the roles for many resource class.
But I want to handle #RolesAllowed to set dynamically instead of defined it as a declarative annotation. Or Is there any other way to handle the role authorization using EJB3 or Java ee security?
Please give your ideas or example to implement it.
Thanks,
Regards,
Ubai
Use #Resource to inject EJBContext (or SessionContext), and call isCallerInRole(String roleName) and throw an exception (or whatever) if it returns false. This is basically what #RolesAllowed does under the covers.
Summary
How do you get the session of a web service client using spring web services and spring security?
Details
After submitting
<form method="POST" action="<c:url value="/j_spring_security_check" />">...</form>
I've noticed that you can:
public class MyUserDetailsService implements UserDetailsService {}
Which will allow you to override methods like loadUserByUsername(String username) therefore being able to retrieve the submitted username and do a database lookup to return a user object.
The issue I have, however, is that I'm unsure where SecurityContextHolder gets set. I'm able to get the user object by using this line of code:
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
But I'm not sure how it gets set in the first place. I would like to know the flow after submitting the above-mentioned form so that I can identify how SecurityContextHolder gets set.
The reason why I want to know this is because I want to use it as a "session" for web service client authentication instead of having the client resubmit credentials with every request.
Spring Version: 3.0.2.RELEASE
/j_spring_security_check is handled by the UsernamePasswordAuthenticationFilter which extends AbstractAuthenticationFilter. The security context is set in the latter's successfulAuthentication method.
However, web-service clients are usually stateless and would be more likely to use something like Basic authentication with a shared secret. I'm not sure there would be much benefit in rolling your own session system based on the security context contents. If you are worried about performance then you could use a cache of authentication information on the server.
I'm running Glassfish 3.0 and I'm implementing JDBCRealm for login authentication. The username and roles are saved in a table called usertable. The authentication is working as expected.
But the problem is now when the user logs in, how can I retrieve the username of the logged in user in the application?
PS: I'm implementing JSF page and Managed Bean
In JSF, you can retrieve the current Principal associated with the request and hence, the current session, using the ExternalContext object, which can be retrieved from the FacesContext. The Principal associated with the request is accessible from the ExternalContext using the getUserPrincipal() method:
FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
The above invocation can be done in a JSF managed bean. You can invoke the getName() method on the Principal object to retrieve the name of the user as a String.
Note that, it possible for you to obtain a Principal instance that references the Anonymous user, if you are retrieving the Principal before authentication, or if the authentication scheme does not protect the entire site.
Request.getRemoteUser or Request.getUserPrincipal, independent of the realm you use for authentication, so if you use a File realm for testing and a JDBC realm for production it will work in both cases. By the way, if you use JDBCRealm also have a look at FlexibleJDBCRealm.
Your authenticate method should return a java.security.Principal which will contain the name.
http://download.oracle.com/javase/1.4.2/docs/api/java/security/Principal.html