How do I get the #AuthenticatedPrincipal from a web socket simpUser? - java

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
}

Related

How to filter data by user in spring boot applcation

I'm making a simple spring boot application and I want to incorporate filtering data by logged-in user or user session. But I don't know what is the best way to set up the application in a way that every user can access data specific to him. I have made the authentification and authorization part of the app.
I'm also working on that kind of application and I've done this by adding as argument#AuthenticationPrincipal CustomUserDetails userDetails to method where you want to get userId. Then you can call: Integer userId = userDetails.getUserId();
So for example something like this:
#GetMapping("/demo")
public String showTemplate(#AuthenticationPrincipal CustomUserDetails userDetails) {
Integer userId = userDetails.getUserId();
return "index";
}
And then you can do with this userId whatever you want. For example, create method in repository findByUserId

ldap & JWT authentication without spring security

I'm trying to create a security module that will check against LDAP for user credentials (on login) and on successful login generate a JWT for further requests to the server.
currently my module works like this:
i have 3 rest API endpoints to provide authentication (login, validate JWT, logout) that are not protected as anyone must be able to access those endpoints,
and also 1 userUpdate endpoint protected with spring security via a JWTAuthenticationProvider
all the stuff pertaining the JWT is ready, now I just need to create a method to check in LDAP if the user and password are correct. but i am having some trouble understanding how am i supposed to do so
i already have the master user and pass to conect to ldap, but most of the examples i find about ldap authentication are with spring security and i dont think thats the way to do it in this case as i need to verify the matching us/pass only on login (and not protect my endpoints with security).
can anyone tell me how im supposed to do that verification? any stuff i am not being clear on? please ask and comment and answer.
thanks
oh one edit:
#Override
public AuthenticationResponse login(AuthenticationRequest authenticationRequest) {
checkNotNull(authenticationRequest, "The authenticationRequest is a required argument!");
AuthenticationResponse authenticationResponse = AuthenticationResponse.builder().build();
//currently a pseudo authentication, here is where i should authenticate against LDAP
Optional<Usuario> optionalUsuario = service.findByNombreUsuario(authenticationRequest);
if (optionalUsuario.isPresent()) {
Usuario usuario = optionalUsuario.get();
String token = JwtTokenUtil.generateToken(authenticationRequest);
authenticationResponse.setAuthenticationToken(token);
repository.saveToken(UserToken.builder()
.nombreUsuario(usuario.getNombreUsuario())
.roles(usuario.getRoles())
.build(), token);
as you can see i intent to make the authentication against ldap only at login, and only to check if the user and pass are correct, i will manage the roles and authorities using other DB
another edit: i have some basic ldap structure for ldap auth using spring security, but i always get bad credentials
edit again: i managed to make it work with spring security, but (as expected) was told by my team that we need to implement that authentication without spring security to integrate with our custom role loader and token creation
use http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/ldap/authentication/LdapAuthenticationProvider.html to authenticate and get roles from LDAP, it should be done using spring security, I probably missed smth but could you explain why you don't want use it as far it is security standart

Set Spring Security Prinicipal in unit test at DAO level

I have a successfully working Spring 4 MVC project with lots of RESTful web-services on the back-end. We use Hibernate 5 and Spring Security 4 as well.
1) We authenticate users from a third-party source, OpenAM 10.x, and this creates a token in the browser.
2) From the front-end, we pass in the Ajax call a request header which contains that OpenAM token.
3) In the back-end, using the SiteMinder example, have a service: CustomUserDetailsService which does the following:
a) this uses our code to openAM and pass in the token
b) we get back JSON data we parse to get the username
c) from there we use the Hibernate Spring Security code to get further details for this user and get the roles
System.out.println("loadUserByUsername: username : " + username);
UserAccountEntity userAccountEntity = userAccountDao.getByUsername(username);
System.out.println("loadUserByUsername: userAccountEntity : " + userAccountEntity);
if (userAccountEntity == null)
{
System.out.println("CustomUserDetailsService: userAccountEntity not found");
throw new UsernameNotFoundException("Username not found");
}
System.out.println("CustomUserDetailsService: START: springframework.user");
// this "User" object is: org.springframework.security.core.userdetails.User
User user = new User(userAccountEntity.getUsername(), userAccountEntity.getPassword(), true, true, true, true,
getGrantedAuthorities(userAccountEntity));
From here, we have working security on the URL endpoints ... this works great!
Now, here is the problem ... my boss wants to use our custom proprietary ACL system to make secure query calls. Making a call to get records, we want to make sure we get only the records the user has access to. We have our own ACL tables that allow us security for a user or role to certain objects. Suffice it to say, this was written before Spring Security ACL ever existed. I'd prefer to use Spring Security 4 ACL, but that is out of the question.
Consider that we have 4 levels, Entity, Dao, Services, Web-Services. A Single controller looks like this:
#RequestMapping(value = "", method = RequestMethod.GET, headers = "Accept=application/json")
public #ResponseBody ArrayList<SponsorEntity> getSponsorList1() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user = null;
if (principal instanceof User)
{
user = ((User) principal);
}
ArrayList<SponsorEntity> sponsorEntityList = (ArrayList) service.getAllList();
return sponsorEntityList;
}
Like I said, this goes through the CustomUserDetailsService and sets the User as defined above. So, the first questions is, in the DAO layer, what is the code I would use to pull this org.springframework.security.core.userdetails.User?
If I can get this User object from the DAO layer, then I can "pipe" that username into our old existing legacy code.
The second question ... in a DAO Unit Test, how can I create/setup this Security? This way I can test to see if my back-end code is really getting the username from an authenticated user.
Please let me know if you need any more information. Thanks!

How to get a custom user logged via InMemoryAuthentication with Spring Security?

I have a Spring MVC web app secured with Spring Security and I'm in the process of writing tests. I'm struggling with getting one of my (custom) user retrieved by Spring Security in its SecurityContextHolder.
Once my user is "inserted" (java-configured) with :
auth.inMemoryAuthentication().getUserDetailsService().createUser(myCustomUser);
I can then create the related token (a UsernamePasswordAuthenticationToken) and ask for Spring to authenticate my user with this token. The problem is Spring doesn't retrieve a custom user instance but an instance of its User class. When Spring looks for such a user in the following method (from Spring's InMemoryUserDetailsManager) :
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails user = users.get(username.toLowerCase());
if (user == null) {
throw new UsernameNotFoundException(username);
}
return new User(user.getUsername(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(),
user.isCredentialsNonExpired(), user.isAccountNonLocked(), user.getAuthorities());
}
It instantiates a new User with the details provided by my configuration.
I don't see the problem with having the InMemoryUserDetailsManager directly returning what was sent to him via the "getUserDetailsService().createUser" call but there must be one probably...
Anyway, I'm probably doing something wrong here, any idea ?
Like suggested, I ended up writing a custom InMemoryUserDetailsManager which I feed my Spring Security configuration with.
To anyone wondering, it seems that it's the only way.

Spring Security and Sessions over Web Services

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.

Categories

Resources