I need to edit the principal id that will be returned to a cas client application.
The principal I need to edit is returned from an external idp which I do not own and its format is like this:
Id: idp autogenerated ID having no meaning for my setup
Attributes:
... Some attributes I do not need ...
**ImportantId**(this is the property I need)
I have read the official documentation so from my understanding the related part of my service json file should be:
...
"usernameAttributeProvider" : {
"#class" : "com.mypackage.cas.principal.MyCustomRegisteredServiceUsernameProvider",
"canonicalizationMode" : "NONE"
In my custom UserNameProvider class, I need to access db in order to get my setup specific username based on the importantId I mentioned above, so I need to do something like this :
public class MyCustomRegisteredServiceUsernameProvider implements RegisteredServiceUsernameAttributeProvider {
#Autowired
UsersService usersService;
#Override
public String resolveUsername(Principal principal, Service service, RegisteredService registeredService) {
// String importantId = ...getting it from principal attributes..
return usersService.getUserNameFromImportant(importantId);
}
}
The problem is that Autowired annotation unfortunately is not working, thus my UsersService is not initialized resulting in a NPE at runtime.
So, firstly I would like to know why my approach is not working and secondly what is the cas "official" way to achieve this behavior?
Cas Version: 5.3.4 Cas overlay template
Env: W10 x64, Java 8
Deployed on Wildfly 12
So, firstly I would like to know why my approach is not working
...because such providers are not spring-managed beans. They are serialized objects found off of JSON documents, and such and never pass through the Spring runtime.
and secondly what is the cas "official" way to achieve this behavior?
One possible workaround would be to remove the injected field and do this in your resolveUsername method:
var appContext = ApplicationContextProvider.getApplicationContext();
var usersService = appContext.getBean("bean-name", UsersService.class);
return usersService.getUserNameFromImportant(importantId);
Related
Working with Spring / Spring security on a small project at the moment and having difficulty implementing this feature. Ideally I only want user1 to view the details of user1 and not those of 2,3 or 4 for example.
I've implemented Spring Security with Roles and understand that I can retrieve a UserDetails object or a principle, I'm not sure exactly but I know I can retrieve the details of the current logged in user using one of, what appears to be many methods.
This is what I'm currently using as a proof of concept when we go to the Admin/home page:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Gamer gamer = gamerService.findGamerByEmail(auth.getName());
System.out.println("Auth: " + auth.getName());
System.out.println("Gamer: " + gamer.getName() + gamer.getId() + gamer.getEmail());
The security config takes care of whether or not the current user can access because of the roles assigned to it.
I believe I should be able to go to the url of /mysite/viewUserDetails and have that page display information of the current user but I cannot find any examples of this, I've found plenty of example that prove a logged in user can view a page but none that specify checks in place to ensure user1 can only view user1's details.
On an older page I do this to display information for a particular user but I understand this to be bad practice-
<a th:href="#{/gamer/{gamerid}/games/excited (gamerid=${gamer.id}) }">
*Worth noting that this isn't using any form of login/registration to pull out this info, I'm simple using the id I pass in as part of the DB query.
It maps onto :
#RequestMapping("/gamer/{gamerid}/games/excited")
public String getExcited(#PathVariable final Long gamerid, Model model){
addGamerListAttributes(model, gamerid, "EXC");
return "games";
}
So my question becomes, and I hope you can point in the right direction, How can I implement a solution where a user can only view his/her details and how should this be represented via the form and connecting controllers as passing ids in the url is kinda ugly (I could use a guid but...)
Thanks so much in advance.
It's actually quite an easy choice. Either you have an entry point like:
#RequestMapping("/gamer/{gamerid}/games/excited")
and you manually check that the user in session can access the requested resource, or you have something like
#RequestMapping("/my-games")
that automatically reads the user id from the security context.
More than a security choice, I'd pick one depending on code reuse and future use-cases (for example the same page/set of pages can be seen by more than one user).
Have a look at #PreAuthorize annotation. It is possbile to annotate given endpoint with it and create custom logic in a bean. Then you can use custom method to allow or disallow the endpoint to proceed :
#Controller
public class HomeController {
#Autowired
private AuthenticationService authenticationService;
#RequestMapping("/gamer/{gamerid}/games/excited")
#PreAuthorize("#authenticationService.hasAccess(#gamerid)")
public String getExcited(#PathVariable final Long gamerid, Model model){
addGamerListAttributes(model, gamerid, "EXC");
return "games";
}
}
Service class :
#Service
public class AuthenticationService {
public boolean hasAccess(String tgamerid) {
//implement logic here
return true;
}
}
Method hasAccess in the AuthenticationService should return boolean. #PreAuthorize will be launched before controller handler method is invoked. The controller above is just an example. You can pass Authentication object in SPeL expression in #PreAuthorize annotation to service method or get it from security context inside service class, to implement logic which fits your needs. More information can be found here and in Spring Docs.
I have a file on a server available via Https I want to access using Spring's Resource abstraction. I want Spring to resolve the resource and inject it into the constructor of my Bean like this:
public class MyClass {
public MyClass(
#Value("https://myserver.com/myfile") Resource resource) {
// do something using the resource
}
}
The issue is that I cannot figure out how to include the username and password for basic authentication into this pattern. I tried the "common" style
#Value("https://username:password#myserver.com/myfile")
but it looks like this is not understood correctly. The server is responding with HTTP status 401 - Unauthorized. I copied the string and perfomed the same query using wget and it worked. So there is no issue with my credentials but most likely with the syntax used to define the resource.
Is there a valid syntax for this in Spring or must I fetch the config in an alternative way setting the Authentication header by hand?
This feels wrong, and I'd prefer it if you didn't do it this way...but you can rely on #Value to inject the property value. Note the use of #Autowired here.
#Component
public class MyClass {
private String resourceUrl;
#Autowired
public MyClass(#Value(${external.resource.url}) String resourceUrl) {
this.resourceUrl = resourceUrl;
}
// The rest of your code
}
Then you could place into the property external.resource.url whichever value you liked...including your full URL with username and password.
I want to call attention that this is probably not a desirable thing to do, since you want to be able to inject the URL, username and password as separate things into your application. This gives you an idea of how you can accomplish it with one component, and while I strongly encourage you to split this up instead (and whatever you do, do not check the properties file in with those values into your source control), I leave the mechanical part of splitting this into more values as an exercise for the reader.
Based on other postings on SO and the web, it would appear that there is no built-in mechanism in a Servlet 3+ container to retrieve the roles from a logged in user, but rather only to check if a user is in a role: request.isUserInRole(String)
But is there any way to retrieve the security-role list as defined for the application?
I find it strange that a LoginModule must persist the principal's credentials but there is nothing defined/related to a principal's roles. At some point, when you call isInRole(), the container must be able to check the list of the user's assigned roles. Is that information not exposed anywhere?
I cannot seem to find any mechanism which allows me to retrieve the defined roles from my deployment descriptor (or via annotations). I'm targeting Wildfly 10/Undertow, but ideally looking for a container agnostic solution.
Is this even feasible? Is there any easy way to programatically retrieve the security-roles defined in my application (either as defined in my descriptor or via #DeclareRoles annotations)?
For retrieve #rolesAllowed annotation I used introspection.
You can do the same to retrieve the defined roles via annotations.
Te reference this in the example is a Servlet.
ServletSecurity ss = this.getClass().getAnnotation(ServletSecurity.class);
for (String role : ss.value().rolesAllowed() ) {
out.print(role + " ");
}
The annotation in the servlet is:
#WebServlet(name = "Coquito", urlPatterns = {"/Coquito"})
#ServletSecurity (#HttpConstraint( rolesAllowed= {"nuevo_menu_intranet"}))
public class Coquito extends HttpServlet {
}
I currently have been reading and trying out MongoDB with Spring REST framework.
I have the following code for the controller:
#RestController
#RequestMapping("/users")
public class UserController {
#Autowired
private UserRepository userRepo;
#RequestMapping(value = "/info2", method = RequestMethod.GET)
public List<User> getAllUser(){
List<User> users = userRepo.findByEmail("test#test.com");
return users;
}
#RequestMapping(value = "/save", method=RequestMethod.POST)
public User createUser(#RequestBody User user){
return userRepo.save(user);
}
}
However, when I call
localhost:8080/users, it returns back
{
_links: {
self: {
href: "http://localhost:8080/users{?page,size,sort}"
templated: true
}-
search: {
href: "http://localhost:8080/users/search"
}-
}-
page: {
size: 20
totalElements: 0
totalPages: 0
number: 0
}-
}
I want the URI /users/info2 to return back the list of users by that particular email. How do I do that?
Also, here are the outstanding questions I have:
Can I just use MongoDBTemplate instead of the MongoRepository? I want more customized queries, and I couldn't find any in depth examples on the web.
How does Spring framework map the xml config file, for example, in cases like when I setup multiple MongoDB connections?
So without your configs, but looking at your existing code and service response, one can make some general assumptions. Your Repository is annotated with #RepositoryRestController which not only provides Spring Data access but also exposes a common ReST endpoint for your repository.
This can be determined from two aspects of your post. First you don't appear to be using HATEOAS in your Controller class, yet your service exposes JSON + HAL. Furthermore your response exposes the paging and sorting feature of Mongo Repository as well as the search behavior of Spring Data Repositories when annotated with #RepositoryRestController.
If you don't want this behavior, change the annotation on your Repository to #Repository instead.
Also to answer your other questions:
1. you can annotate methods if you want with queries on Spring Data Repositories, you can also use any class in the stack managed by spring you want, but why?
I suggest reading about the bean lifecycle to understand the dependency management within spring, there are plenty of presentations (including one in my github repo). If you have multiple connections, you can define your repository beans to utilize anything you wire it. There is a lot more manual operations at that point, and it will take some understanding and through to make it work. There is no way to give you a simple "do xyz" type answer without a lot more information.
I have a controller (Spring Controller) that will serve json to a mobile app.
Various servers run our software. Not all will be configured to serve mobile requests.
I've added a bean of class Integer with the id of an object containing various system parameters necessary to handle requests.
This bean is defined in xml and autowired into the controller.
The autowiring uses (required = false) so we can run without a value defined in xml.
I have checked and found that the autowired Integer is indeed null if not defined in xml.
What I would like to do now is add to my requestmappings in a way that will match one method if that Integer is null and the regular method when the Integer is not null (basically, we'll reply with a standard json error object).
This seems like it'd be pretty straightforward with some sort of AOP, but I've little experience aside from using Spring. Most conditional info in the Requestmapping annotation seems to be based on request parameters, not server-side variables.
Any ideas?
I think that is better use a property-placeholder to load a properties file from the classpath. In this way you can deploy the same war file in different servers and use a different property file for each server (putting it in the AS classpath).
Once you did it you can use a variable in your controller (or in an interceptor if you want to leave the controller's code clean) and do something like this:
#Controller
public class MyController{
#Value("${mobile.enabled}")
private boolean mobileEnabled;
#RequestMapping("/mobile")
public Object json(){
if (!mobileEnabled)
throw new IllegalStateException("This server can't do it!");
}
//create the json
return result;
}
And a properties file like:
mobile.enabled=true
when you want to enable it, or false when don't.