There's a lot of documentation on how to use jsp tags, aop, annotations, the application context, and all of these sorts of things... but how do I access the access control methods directly? What class do I need to create, if any? Is there hidden bean I need to be aware of? It doesn't seem like SecurityContextHolder is the right place to look.
What I'd like to do is something like this:
if(springSecurityObject.isAuthorized("hasAnyRole('DIRECTOR', 'ADMIN')")) {
// ... do something
}
Or even better:
if(springSecurityObject.hasAnyRole('DIRECTOR', 'ADMIN')) {
// ... do something
}
Thanks!
EDIT: It seems like the spring security people are using the granted authorities on the user object itself:
https://fisheye.springsource.org/browse/spring-security/taglibs/src/main/java/org/springframework/security/taglibs/authz/AbstractAuthorizeTag.java?r=fc399af136492c6c37cdddca6d44e5fe57f69680
I think it would probably have been helpful if they abstracted out a ton of this code and put it into a nice set of classes instead - something that both the tag libraries and actual users could use. They are private helper methods after all... a common smell that they should probably exist in some classes instead.
Since they are doing the plumbing manually, I guess I have to assume that what I want doesn't exist.
The only thing I can think of is invoking your UserDetailsService manually, calling getAuthorities() on the returned Authentication and then calling contains() or containsAll() on the returned collection.
So you'd have something like:
final UserDetails jimmyDetails = myDetailsService.loadUserByUsername("Jimmy");
final Collection<GrantedAuthority> jimmyAuthorities = jimmyDetails.getAuthorities();
// make it a Collection<String> by iterating and calling .getAuthority()
plainAuthorities.contains("ROLE_YOU_NEED_TO_CHECK_FOR");
Writing your own helper methods that do this would not be too hard, although I agree that having them in the API would be nice.
Related
I'd prefer it as a record as there is less boilerplate, but would there be issues?
IntelliJ is suggesting that I turn a basic Java class #Service like this:
#Service
public class LocationService {
private final PlaceRepository placeRepository;
#Autowired
public LocationService(PlaceRepository placeRepository) {
this.placeRepository = placeRepository;
}
public List<PlaceDto> findPlacesByRegionId(Long regionId){
return placeRepository.findByRegionId(regionId).stream().map(place -> new PlaceDto(place.getId(), place.getName())).toList();
}
}
into a Java record #Service like this:
#Service
public record LocationService(PlaceRepository placeRepository) {
public List<PlaceDto> findPlacesByRegionId(Long regionId) {
return placeRepository.findByRegionId(regionId).stream().map(place -> new PlaceDto(place.getId(), place.getName())).toList();
}
}
You could do that, but records have getters (well without get prefix). Which Service Layer shouldn't have. Your Service Facade exposes public methods which also are usually #Transactional, you don't want to mix them with methods that no one is going to use.
Also, records define equals() & hashCode() which aren't needed for Service classes either.
In the end the only common theme between Records and Services is that all fields are usually final and all of them are usually passed via constructor. This isn't much of commonality. So it sounds like a bad idea to use records for this.
Let me quote Oracle guy:
JEP 395 says:
[Records] are classes that act as transparent carriers for immutable
data.
So by creating a record you're telling the compiler, your colleagues,
the whole wide world that this type is about data. More precisely,
data that's (shallowly) immutable and transparently accessible. That's
the core semantic - everything else follows from here.
If this semantic doesn't apply to the type you want to create, then
you shouldn't create a record. If you do it anyways (maybe lured in by
the promise of no boilerplate or because you think records are
equivalent to #Data/#Value or data classes), you're muddying your
design and chances are good that it will come back to bite you. So
don't.
UPD.
I have spent a couple of minutes to figure out what was the root cause of your statement that "IntelliJ is suggesting that I turn a basic Java class #Service like this". And have found the following discussion: https://youtrack.jetbrains.com/issue/IDEA-252036
Thereby:
using records for spring beans is definitely a bad idea: such beans are not eligible for auto proxying, moreover records are not designed for such scenarios
it is embarrassing but JetBrains does mislead CE users
I have been reading a lot online/offline about where to put validation and business rules in general for domain driven design. What I could not understand is how can an entity provides methods that does validation and business rules without resorting to static methods or having a service? This is especially important for cases where the domain object does not need to be instantiate yet, but we need to validate a value that will eventually used to set the object's attribute.
I noticed blog postings such as http://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/ relies on .NET's specific extension method, which is not available in programming languages such as Java. I personally don't like static methods are they cannot be overridden and hard to test.
Is there anyway I could do this without static methods or having to instantiate an unnecessary domain object just to use its validation and business rules methods. If not, does that mean domain driven design is very dependent on static methods?
Thanks
Use ValueObjects Not Entity.
In the registration case, a UserName value object could be introduced. Create a Username object when receiving the registration. Implement validation in the constructor of the UserName.
See this question and this presentation for more detail.
Edit1:
1.How to handle cases where different validation rules applied for different context. For example: The username must not have numbers for certain type of members, but it is required for other types of members?
Maybe different factory methods could do that. like UserName.forGoldenCardMember(...) or UserName.forPlainMember(...). Or make MemberType (a hierachy maybe) to validate UserName.
Another alternative solution is use AggregateFactory(AccountFactory in this case).
2.Is constructor the only place to put the validation code? I did read online about two points of view: an object must always be valid vs. not always. Both present good arguments, but any other approach?
I prefer valid approach personally. Passing an maybe invalid value object harms encapsulabilty.
Edit2:
Require
a) validation business rule based on context(different username rules for member types)
b) keep validating all business rules even if one of them fail
Stick with Single responsibility principle by using Value Object(MemberType this case).
AggregateFactory could be introduced to ease the application layer(coarser granularity).
class AccoutFactory {
Account registerWith(Username username, MemberType type, ....) {
List<String> errors = new ArrayList<String>();
errors.addAll(type.listErrorsWith(username));
errors.add(//other error report...
if (CollectionUtils.isEmpty(errors)) {
return new Account(username,....);
} else {
throw new CannotRegisterAccountException(errors);
}
}
}
Edit3:
For questions in the comments
a) Shouldn't the Username object be the one that has a method that returns the error like
the listErrorsWith()? After all, it is the username that has different rules for different member type?
We could check this question from another perspective: MemberTypes have different rules for username. This may replace if/else block in the Username.listErrosWith(String, MemeberType) with polymorphism;
b) If we have the method in the MemberType, the knowledge will not be encapsulated in the Username.Also, we are talking about making sure Username is always valid.
We could define the validity of Username without MemberType rules. Let’s say "hippoom#stackoverflow.com" is a valid username, it is a good candidate for GoldenCard member but not good for SilverCard member.
c) I still can't see how performing validation that returns a list of errors without getting the list from exception thrown by the constructor or static method. Both does not look ideal IMHO.
Yes, the signature of listErrorsWith():List looks weired, I'd rather use validate(username) with no returning value(throw exception when fails). But this will force the cilent to catch every validation step to run validations all at once.
If you decided to use DDD in your application you need to build more complex solution. I agree with #Hippoom, you shouldn't use Entity for this purpose.
I would suggest this solution:
DTO -> Service Layer (ValidationService -> Converter) -> Persistence Layer (Repository)
Some explanation:
When you received DTO from client side with all necessary parameters, you should validate it in you service layer (e.g. Use another service like ValidationService) which can throw exception if something wrong. If all Ok, you can create Entity from your DTO in Converter and persist it in Repository.
If you want flexible solution for ValidationService I'd suggest Drools
I work with a dynamic Dataset model, which (in short) takes in attributes and stores them in a Map like this...
Dataset dataset = new Dataset();
dataset.setAttribute("name", "value");
...for later recovery, like this...
String value = dataset.getAttribute("name");
...and that has worked wonderfully for my purposes. But now I'm in a place where I'd like to use a templating engine to dynamically generate HTML. In the template, it's not ideal for me to do a lot of ${dataset.getAttribute("name")}. It would be rather nice if I could create artificial methods whenever something was added to a Dataset. For instance, if I did this...
dataset.setAttribute("name", "value");
...I'd like to be able to retrieve it like this...
String name;
name = dataset.name;
//or
name = dataset.getName();
...but so far I haven't been able to pull it off. What approach might I take here? Is it even doable?
Edit:
I understand that Velocity offers Property Lookup Rules to try to resolve dataset.name to dataset.get("name"), and that's great, but I need to know how to achieve this in the case that Velocity isn't the target as well.
See http://velocity.apache.org/engine/releases/velocity-1.5/user-guide.html#propertylookuprules
If your method was named get(String attribute) rather than getAttribute(String attribute), you could use the same syntax as for regular properties. So, either refactor your class, or add an additional get method that does the same thing as getAttribute, or transform your object into a Map, which has a get method.
In the past I have generated POJOs dynamically with Objectweb's ASM. This has the benefit that the underlying fields are type safe and much more efficient (esp for privative values)
You can use Dynamic Spring proxies with AOP technology or CGLib proxies. AOP could be used to describe getters like this : execution(public * com.bla.YourClass.get*())")
From what I've seen, it's fairly common for template engines for Java to support both
getters/setters of the form getAttribute, and
implementation of the Map interface
Before you spend too much time looking for a more generic solution (assuming the above won't be supported like it is in Velocity), it's probably worth taking a look at the other engines to see if any of them don't support it. If all your possible targets do, then you're probably fine relying on it.
I'm a big fan of making sure you actually have a problem before you spend the time to solve it.
Jacob Orshalick (author of Seam Framework: Experience the Evolution of Java EE ) said:
Outjection allows you to make variables available from the current context for injection or access through EL. This can be beneficial if you want to loosely couple several components that inject the same context variable (like the current user, the hotel being booked, etc). If you want to avoid outjection, an alternative is to use an #Factory method or set the value directly into the context through: Contexts.getConversationContext().set("myVarName", myVar)
Another benefit is performance. By outjecting a value to the context, you can bypass having to pass through your component to get that value. This is especially applicable in the case of data tables with JSF (see this discussion). But, as you will see in the discussion you could also use #BypassInterceptors to achieve the same benefit.
Outjection is really a convenience, but the same benefits can definitely be achieved through other means. Do note that outjection was not included in Web Beans and will either be deprecated or completely removed in Seam 3, so this is further reason to avoid it when possible.
We have an application with a lot of outjections and we've started to get rid of them. He said:
but the same benefits can definitely be achieved through other means.
but which are these other means? How to remove the outjections? In ASP.NET for instance you have session variables. In Seam, you can outject var in session (a benefit in some situations).
Or page scope: (for instance in jsf cycle the backing bean is called multiple times (sometimes). You have an account which is loaded from an accountId page param. You can load the account, outject it with a page scope and you can use its properties greatly. OR (to avoid outjection) is to have a loadAccount() method where you take the account from the db whenever you need it...WORST!)
I do not think that:
Contexts.getConversationContext().set("myVarName", myVar)
is a method of how to avoid outjection.
This only calls the same context where the outjected variable is saved and modifies it in a profound way (i think it's exactly what #Out do in the background).
Question 1: What do you think guys about their intention? Do you have specific info about how they will replace it?
Question2: How do you avoid the use of outjection?
Thanks in advance.
I think the best way you can achieve "outjection" is by using #Factory. Its advantage:
It can be #In-jected into another component
It can create any value, not just component instance
It calculate the value once, and just once
It can be triggered by JSF page (I am not sure whether you must enable Seam Transaction Management in order to get this feature)
So if you have a JSF page that needs to access a #Factory more than one time, It is calculated just once. If a value needs to be calculated each time it is requested, so you need a #Unwrap method. For instance, #{currentDate} built-in component is implemented as follows
#Name("org.jboss.seam.faces.facesContext")
#Scope(ScopeType.STATELESS) // ScopeType.STATELESS is similar to Spring prototype scope
public class CurrentDate {
#Unwrap
public Date getCurrentDate() {
return new java.sql.Date(System.currentTimeMillis());
}
}
regards,
To avoid outjection just add a getter to your field in your backing bean, so instead of:
#Name("myBean")
public class MyBean{
#Out
private SomeBean someBean;
}
you will have:
#Name("myBean")
public class MyBean{
private SomeBean someBean;
public SomeBean getSomeBean(){
return someBean;
}
}
and in your xhtml/jsp file you will have to call the getter instead but this have some issues too because everytime you call the getter all the Seam Interceptors will be applied to that call so you probably will need to add #BypassInterceptors to prevent that from happening.
And yes I also think that
Contexts.getConversationContext().set("myVarName", myVar)
is just doing what outject does but manually.
I have the following situation: my application's authorization mechanism is implemented using Spring security. The central class implements AccessDecisionManager and uses voters (each of which implements AccessDecisionVoter) to decide whether to grant access to some method or not. The algorithm that tallies the votes is custom:
public class PermissionManagerImpl extends AbstractAccessDecisionManager {
public void decide(
Authentication authentication,
Object object,
ConfigAttributeDefinition config) throws AccessDeniedException {
Iterator<?> iter = getDecisionVoters().iterator();
boolean wasDenied = false;
while (iter.hasNext()) {
AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();
int result = voter.vote(authentication, object, config);
switch (result) {
// Some tallying calculations
}
}
if (wasDenied) {
throw new AccessDeniedException("Access is denied");
}
}
}
Upon denying an access to some method, the client of the application is interested in obtaining an informative exception that specifies exactly why the access is denied. This implies passing some information from voters to the decision manager. Unfortunately, the only information the standard AccessDecisionVoter passes back to the decision manager is one of the possible return values (ACCESS_GRANTED, ACCESS_ABSTAIN or ACCESS_DENIED).
What is the best way to do it?
Thanks.
Well, the AccesssDecisionVoter interface actually returns an int in this situation. Granted, the built-in voter implementations always only return one of the three constants you mentioned (and these are what the standard access decision managers check for), but then they don't really have anything extra to return - the RoleVoter for instance will deny access if and only if the principal doesn't have the required role.
Since you're using your own implementations both of the voters and the access decision manager, you have several options available as I see it:
Return other values of integers as some form of error code; treat ACCESS_GRANTED, ACCESS_ABSTAIN and ACCESS_DENIED as their typical values, but treat any other integer as "access denied" with an error code. Ideally have a lookup table of error codes available - essentially a poor man's enum.
Within your voter, return ACCESS_DENIED as usual, and set some publically accessible property (either on the voter object itself or perhaps some statically-accessible field) with the error reason. In your manager, if you get access denied from your custom voter, check the property to get the details.
As above, set an error property within the voter; but ensure that the instance of Authentication being passed in is one of your own custom subclasses that provides a good
location to set/retrieve this information.
Throw an AccessDeniedException (or suitable subclass) from within your voter itself. This is not ideal as it presupposes the logic in the access decision manager; but you could either let this bubble straight up, or if needed catch it within the manager (a custom subclass would definitely be good for this) and rethrow if access really is denied (something similar to what the ProviderManager class does with its lastException variable).
None of these sticks out as the obviously correct and elegant answer, but you should be able to get something workable from whichever one is most appropriate. Since there is no explicit support within the voter framework for communicating reasons (it's a straight boolean response fundamentally) I don't think you can do much better.
Thanks for people who answered.
I think I have found a quite elegant way to do what I wanted and still use the standard voters API. The 2nd parameter to the vote method of AccessDecisionVoter is the secured object. I can create a contract between the decision manager and the voters, that this object is of a specific class/interface that is a wrapper, through which the original secured object can be fetched and also additional information can be added by the voters that deny the access.
I saw a pattern like this in other frameworks as well. This solution has the following advantages over other possible solutions:
The voters can remain stateless, so they can be singletons
The standard interface of the AccessDecisionVoter is used and no new return values are added
The additional information is saved in an object that is discarded automatically because no one uses it after the AbstactDecisionManager's decide method, so no cleanup code is required
Cheers.
Can't you implement AccessDecisionManager directly, without using the voters? You can then throw an AccessDeniedException with the correct information. Maybe RoleVoters are not the right abstraction to use in your case.