I have a problem with isCallerInRole method from the SessionContext. The application run on Glassfish 2.1 and uses JDK6.
In the following class, I'm exposing two methods that ascertain if the current user has a specific role or not. In particular, I'm going to check for two specific roles, say Role1 and Role2. CheckRemote is the interface for CheckFacade.
#Stateless
#DeclareRoles({"Role1", "Role2"})
public class CheckFacade implements CheckRemote {
#Resource
private SessionContext ctx;
#Override
public Boolean hasRole1() {
return ctx.isCallerInRole("Role1");
}
#Override
public Boolean hasRole2() {
return ctx.isCallerInRole("Role2");
}
}
When I go to call hasRole1() or hasRole2() I always get false as result, even if the user has the role.
Now, if I consider the following version that is focused only on one role, then everything works fine, i.e. I get false or true if the user has not the role or has the role, respectively.
#Stateless
#DeclareRoles("Role1")
public class CheckFacade implements CheckRemote {
#Resource
private SessionContext ctx;
#Override
public Boolean hasRole1() {
return ctx.isCallerInRole("Role1");
}
}
Maybe I'm missing something. Any idea?
Related
I have two classes
public class MyTest {
#Autowired
private MyService myService;
private void test() {
myService.writeToDb();
}
}
#Service
public class MyService {
#Transactional
public void writeToDb() {
// do db related stuff
}
}
I want to know if calling a method test() (which is a private method) from MyTest class would create a transaction.
P.S
I'm using Spring Boot. And Java 17.
It will work, whether you call the method of another object from a public or private method inside yours is an implementation detail. From callee's point of view, it's the same, it is not even aware of the caller's context.
Spring AOP uses the Proxy pattern to handle those scenarios. It means you are not directly receiving a MyService bean, but a MyServiceSpringCreatedProxy (not the actual name, check in debug mode and you'll see), which is actually handling transactions around methods.
So as long as the call passes through the Spring's proxy, the #Transactional will be accounted for as expected. Bear in mind that it doesn't mean a new transaction is open, it depends if another already exists and your configuration.
However, any self call (to a public or a private method) would not pass through the proxy and then #Transactional would not be working.
#Service
public class MyService {
// can be private, public or whatever
public void callRelatedStuff() {
//self call, no transactional work done
writeToDb();
}
#Transactional
public void writeToDb() {
// do db related stuff
}
}
First of all, I'm a relative noob to Spring Boot, so keep that in mind.
I've got a REST api in which I'm trying to minimize database calls for the same object and I've determined that using a Spring Bean scoped to the Request is what I want. Assuming that is correct, here is what I'm trying to do:
1) Controller takes in a validated PhotoImportCommandDto command
PhotoCommandController
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> importPhoto(#Valid #RequestBody PhotoImportCommandDto command){
...
}
2) PhotoImportCommandDto is validated. Note the custom #UserExistsConstraint which validates that the user exists in the database by calling a service method.
PhotoImportCommandDto
#Component
public class PhotoImportCommandDto extends BaseCommand {
#NotNull(message = "userId must not be null!")
#UserExistsConstraint
private Long userId;
...
}
What I would like to do is somehow set a Spring Bean of the user that is validated in the #UserExistsConstraint and reference it in various methods that might be called throughout a Http request, but I'm not really sure how to do that. Since I've never really created my own Spring Beans, I don't know how to proceed. I've read various guides like this, but am still lost in how to implement it in my code.
Any help/examples would be much appreciated.
You can use the #Bean annotation.
#Configuration
public class MyConfiguration {
#Bean({"validUser"})
public User validUser() {
User user;
//instantiate user either from DB or anywhere else
return user;
}
then you can obtain the validUser.
#Component
public class PhotoImportCommandDto extends BaseCommand {
#Autowired
#Qualifier("validUser")
private User validUser;
...
}
I don't really know how to make annotations in Java. Anyway, in Spring, checking where the User exists in the DataBase or not is one line of code:
userRepository.findOne(user) == null
That is accomplished by the Spring Data JPA project:
Create a JPA Entity User.
Set the spring.datasource.url and login/password in the
resources/application.properties.
Create this interface:
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
}
Note, Spring implements it behind the scences.
Inject this interface into your RestController (or any other Spring bean):
private UserRepository userRepository ;
**constructor**(UserRepository ur){
userRepository = ur;
}
Note, a Spring Bean is any class annotated #Component (this includes stereotype annotations like Controller, Repository - just look up the contents of an annotation, it may use #Component internally) or returned from a method which is annotated #Bean (can only be on the Component or Configuration class). A Component is injected by searching the classpath, Bean is injected more naturally.
Also note, injecting is specifying #Autowired annotation on field or constructor, on a factory method, or on a setter. The documentation recommends that you inject required dependencies into constructor and non-required into the setter.
Also note, if you're injecting into a constructor and it is clean by the arguments, you may omit #Autowired annotation, Spring will figure it out.
Call its method findOne.
So, you can do one of the following:
Inject the userRepository into the #RestController constructor (as shown above). I would do that.
Inject the userRepository into the #Service (internally #Component) class that will do this sorts of thing for you. Maybe you can play with it to create an annotation.
p.s. Use #PostMapping instead of #RequestMapping(method = RequestMethod.POST)
p.p.s. If ever in doubt, go to the official documentation page and just press CTRL-F: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/ Note the current word, that will always take you to the latest version.
p.p.p.s Each Spring project has its own .io webpage as well as quick Get Started Guides where you can quickly see the sample project with explanations expecting you to know nothing.
Hope that helps! :)
Don't forget to mark the answer as accepted if you wish
Using Jose's input, I took a bit of a different route.
Here's what I did:
I created a ValidatedUser class:
#RequestScope
#Component
public class ValidatedUser {
private UserEntity user;
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
}
and I also created a wrapper class HttpRequestScopeConfig to capture all variables to use over the course of an Http Request to the api.
#Component
public class HttpRequestScopeConfig {
#Autowired
private ValidatedUser validatedUser;
...
public UserEntity getValidatedUser() {
return validatedUser.getUser();
}
public void setValidatedUser(UserEntity validatedUser) {
this.validatedUser.setUser(validatedUser);
}
...
}
In my UserExistsConstraintValidator (which is the impl of #UserExistsConstraint, I set the validatedUser in the httpRequestScopeConfig:
public class UserExistsConstraintValidator implements ConstraintValidator<UserExistsConstraint, Long> {
//private Log log = LogFactory.getLog(EmailExistsConstraintValidator.class);
#Autowired
private UserCommandService svc;
#Autowired
private HttpRequestScopeConfig httpRequestScope;
#Override
public void initialize(UserExistsConstraint userId) {
}
#Override
public boolean isValid(Long userIdField, ConstraintValidatorContext context) {
try {
UserEntity user = svc.findUserOfAnyStatus((Long) userIdField);
if (user != null) {
httpRequestScope.setValidatedUser(user);
return true;
}
} catch (Exception e) {
//log.error(e);
}
return false;
}
}
Now, I can access these variables throughout the rest of my service layers by autowiring HttpRequestScopeConfig where necessary.
I am currently implementing Spring Security in my application. I did manage to put #Secured annotation on my service that getAllUsers() from the database, and it is working fine as long as the user is identified (depending on his rights, he can get or not the list of users).
But I have a #Scheduled method in charge of indexing all users, and when it is launched it call the same protected getAllUsers() method, and obviously crashes as it is not logged in : I get the following exception :
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
I'm currently thinking of one possible solution, which would be to mark the internal methods with a custom annotation, which would be retrieved by a custom AccessDecisionVoter allowing the caller to call the protected method.
I'm looking for best practice for this kind of usecase
Because method is #Secured and spring expect security authentication object in context. Here is working example of AccessDecisionVoter Spring-security - AccessDecisionVoter-impl wont be invoked
or if u will have filters or smth which will depends on user context values this one should be ok
#Scheduled
public void method() {
try {
ScheduledAuthenticationUtil.configureAuthentication();
// do work
}
catch(Exception e) {
e.printStackTrace();
}
finally {
ScheduledAuthenticationUtil.cleanAuthentication();
}
}
private static class ScheduledAuthenticationUtil {
public static void configureAuthentication() {
// inject auth obj into SecurityContextHolder
}
public static void cleanAuthentication() {
// SecurityContextHolder clean authentication
}
}
I assume your service class looks like :
public class MyServiceImpl implements MyService {
...
#Secured
public Xxx getAllUsers() {
...
// call DAO
...
return xxx;
}
...
}
And you call myService.getAllUsers() from the #Scheduledclass.
The simplest way is to split getAllUsers and make the service class inherit from 2 interfaces, one containing the secured method, and one that would contain a publically accessible version :
public class MyServiceImpl implements MyService, MyScheduledService {
...
#Secured
public Xxx getAllUsers() {
return restrictedGetAllUsers;
}
public Xxx restrictedGetAllUsers() {
...
// call DAO
...
return xxx;
}
...
}
public interface MyService {
Xxx getAllUsers();
}
public interface MyScheduledService extends MyService {
Xxx restrictedGetAllUsers();
}
Then in your controller class :
#Autowired MyService myService => will call only getAllUsers()
and in your #Scheduled class :
#Autowired MyScheduledService myService => will call restrictedGetAllUsers()
All that may seem overcomplicated, but as your scheduled class and you controller have no reason to call the service methods the same way, it make sense to present them two different interfaces with different security requirements.
I went with kxyz answer, improved with a service that run a piece of code by setting the wanted Authorities before running the code, and putting back the previous authorities when the code is done :
public void runAs(Runnable runnable, GrantedAuthority... authorities) {
Authentication previousAuthentication = SecurityContextHolder.getContext().getAuthentication();
configureAuthentication(authorities);
try {
runnable.run();
} finally {
configureAuthentication(previousAuthentication);
}
}
protected void configureAuthentication(GrantedAuthority... authorities) {
Authentication authentication = new UsernamePasswordAuthenticationToken("system", null, Arrays.asList(authorities));
configureAuthentication(authentication);
}
protected void configureAuthentication(Authentication authentication) {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
Reffers to PhilippeAuriach answer - there is a better way to run new thread with authorites - with spring security extended runnable method, context from main thread is copied into delegated runnable
public void authorizedExecute(Runnable runnable) {
new Thread(new DelegatingSecurityContextRunnable(runnable)).start();
}
I want to implement a public/global variable so that I can access from any layer(controller/service/dao) of a spring project. For example
class Abc{
public User user;
public String subdomain;
}
Now I want to get user, subdomain values from any layer. But remember that, my project has user management. So I need to specific value for each user session.
Note:
The life cycle of this values is session
This is not singletone forall users
This is specific per session
Thanks
A possible solution is to have a service which has the ability to lookup the currently logged on user, and provides the context information you require. As #siledh mentioned, once you have this information, you can then pass it into layers where you do not want to have any concept of context (e.g. in your DOAs)
#Service
public class ContextService {
public User getLoggedOnUser() {
// Get user id/username from Spring Security principal
// Use id/username to lookup the User
// Return the logged on user
}
}
#Controller
public class SomeController {
#Autowired
private ContextService context;
#Autowired
private SomeReposity someReposity;
#RequestMapping("/home")
public String homePage() {
User loggedOn = contextService.getLoggedOnUser();
String userInformationNeededForHomePage =
someReposity.findSomethingForUser(loggedOn);
...
}
}
#Repository
public class SomeReposity {
public String findSomethingForUser(User user) {
// find something
}
}
I'm using boolean switchers to resolve a choosed behaviour of application, for example SAVEACCEPTED enables SAVE button of form.
<h:commandButton action="#{bean.save}" disabled="#{!bean.saveaccepted}">
JSF need private boolean and its getters and setters, but if I want to resolve some internal logic in application server, it must be defined static. For example
IF (USERFOUND) SAVEACCEPTED = true;
So, I'm using settings class and there are public static booleans defined. And in the beans there are getters and setters pointing to the Settings.VARIABLE
Settings.java
public static boolean SAVEACCEPTED = false;
Bean.java
public static boolean isSaveAccepted() {
return Settings.SAVEACCEPTED;
}
Problem is, that the public boolean is only one and if more then one users using an application, when the first switch the variable, it affects second user form.
How can I solve this issue, is there some standard solution?
Don't use a static variable. Use a #SessionScoped or #ViewScoped bean to store the settings separately for each user.
#Named
#SessionScoped
public class Settings
{
private boolean saveAccepted = false;
public boolean isSaveAccepted()
{
return saveAccepted;
}
public void setSaveAccepted(boolean saveAccepted)
{
this.saveAccepted = saveAccepted;
}
}
and
<h:commandButton action="#{bean.save}" disabled="#{!settings.saveaccepted}">
What if i'd need to set the saveAccepted = true in another bean (not in JSF)? It doesn't work, because in that case, saveAccepted have to be static.
Do not use a static variable.
If you need to set the value in another bean, you can #Inject an instance:
#Named
#RequestScoped
public class SomeOtherBean
{
#Inject
private Settings settings;
public boolean getSaveAccepted()
{
return settings.getSaveAccepted();
}
public void setSaveAccepted(boolean saveAccepted)
{
settings.setSaveAccepted(saveAccepted);
}
}
and CDI will give you the right instance of Settings.
BalusC comments:
Based on the question history, OP is using Tomcat which is just a simple servletcontainer.
Since it looks like you're not using a full Java EE 6 container, you can use #ManagedBean instead of #Named and #ManagedProperty instead of #Inject.
#ManagedBean
#RequestScoped
public class SomeOtherBean
{
#ManagedProperty
private Settings settings;
public boolean getSaveAccepted()
{
return settings.getSaveAccepted();
}
public void setSaveAccepted(boolean saveAccepted)
{
settings.setSaveAccepted(saveAccepted);
}
}
My apologies for sending you down a more complicated path!
Using static variable in this scenario is not ideal. Static fields by definition are shared across all instances of the class. So what is happening is the value you are storing are getting shared for all instances of your managed bean.
I recommend you save it at the request scope with #ViewScoped or define it in the faces-config.xml with <managed-bean-scope>.