I used Java EE 6 with Glassfish v3.0.1, and I wonder if Java EE security model support ACL, and if so how fine-grained is it get?
EDITED
I implement Security using jdbc realm via glassfish v3, that the realm at runtime look into table USER inside the database to check for authentication, by looking at the password field and authorization by looking at the role field. The roles field only contain 2 either ADMINISTRATOR or DESIGNER. So it is a One-to-one map between user and role. At the managed bean level, I implemented this
private Principal getLoggedInUser()
{
HttpServletRequest request =
(HttpServletRequest) FacesContext.getCurrentInstance().
getExternalContext().getRequest();
if(request.isUserInRole("ADMINISTRATORS")){
admin = true;
}else{
admin = false;
}
return request.getUserPrincipal();
}
public boolean isUserNotLogin()
{
Principal loginUser = getLoggedInUser();
if (loginUser == null)
{
return true;
}
return false;
}
public String getLoginUserName()
{
Principal loginUser = getLoggedInUser();
if (loginUser != null)
{
return loginUser.getName();
}
return "None";
}
by calling isUserInRole, I can determine if the user is admin or not, then the JSF will render the content appropriately. However, that is not fine-grained enough (real quick background info: There are multiple projects, a project contains multiple drawings). Because if u are a DESIGNER, you can see all the drawings from all the projects (what if I only want tom to work on project A, while peter will work on project B, Cindy can supervised over the two project A and B). I want that, at runtime, when I create the user, I can specifically set what project can he/she see. Is there a way to accomplish this? NOTE: There are more than just two projects, the above example is just for demonstration.
The Java EE security model authenticates a 'Principal' which may one have or more 'Roles'.
In the other dimension you have services and resources which need configurable 'Permissions' or 'Capabilities'.
In the configuration you determine which 'Principals' or 'Roles' have which 'Permissions' or 'Capabilities'.
In other words, yes it supports ACL and it is as fine grained as you want it to be, but you'll have to get used to the terminology.
In the answer of Vineet is the excellent suggestion to create 'roles' per project id. Since people must be assigned to projects anyhow, it is straightforward to to add the people to these groups at that time. Alternatively a timed script can update the group memberships based on the roles. The latter approach can be preferable, because it is easier to verify security if these decisions are in one place instead of scattered all over the administration code.
Alternatively you can use "coarse-grained" roles e.g. designer and make use of the database (or program logic) to restrict the views for the user logged in
SELECT p.* FROM projects p, assignments a WHERE p.id = a.projectId AND a.finishdate < NOW();
or
#Stateless class SomeThing {
#Resource SessionContext ctx;
#RolesAllowed("DESIGNER")
public void doSomething(Project project) {
String userName = ctx.getCallerPrincipal.getName();
if (project.getTeamMembers().contains(userName) {
// do stuff
}
}
}
Note that the coarse grained access control has here been done with an annotation instead of code. This can move a lot of hard to test boilerplate out of the code and save a lot of time.
There are similar features to render webpages where you can render parts of the screen based on the current user using a tag typically.
Also because security is such a wide reaching concern, I think it is better to use the provided features to get at the context than to pass a battery of boolean flags like isAdmin around as this quickly becomes very messy. It increases coupling and it is another thing making the classes harder to unit-test.
In many JSF implementations there are tags which can help rendering optional things. Here is are examples for richfaces and seam:
<!-- richfaces -->
<rich:panel header="Admin panel" rendered="#{rich:isUserInRole('admin')}">
Very sensitive information
</rich:panel>
<!-- seam -->
<h:commandButton value="edit" rendered="#{isUserInRole['admin']}"/>.
Here is an article explaining how to add it to ADF
The Java EE security model implements RBAC (Role Based Access Control). To a Java EE programmer, this effectively means that permissions to access a resource can be granted to users. Resources could include files, databases, or even code. Therefore, it is possible to not only restrict access to objects like files and tables in databases, it is also possible to restrict access to executable code.
Now, permissions can be grouped together into roles that are eventually linked to users/subjects. This is the Java EE security model in a nutshell.
From the description of your problem, it appears that you wish to distinguish between two different projects as two different resources, and therefore have either two separate permission objects or two separate roles to account for the same. Given that you already have roles (more appropriately termed as user groups) like Administrator, Designer etc. this cannot be achieved in quite easily in Java EE. The reason is that you are distinguishing access to resources to users in a role, based on an additional property of the resource - the project ID. This technically falls into the area known as ABAC (Attribute Based Access Control).
One way of achieving ABAC in Java EE is to carry the properties/attributes granted to the role, in the role name. So instead of the following code:
if(request.isUserInRole("DESIGNERS")){
access = true;
}else{
access = false;
}
you ought to doing something like the following. Note the ":" character used as a separator to distinguish the role name from the accompanying attribute.
if(request.isUserInRole("DESIGNERS"+":"+projectId)){
access = true;
}else{
access = false;
}
Of course, there is the part where your login module should be modified (either in configuration or in code) to return Roles containing project IDs, instead of plain role names. Do note that all of these suggested changes need to reviewed comprehensively for issues - for instance, one should be disallowing the separator character from being part of a role name, otherwise it is quite possible to perform privilege escalation attacks.
If implementing the above proves to be a handful, you could look at systems like Shibboleth that provide support for ABAC, although I've never seen it being used in a Java EE application.
Related
I'm new to "normal" back-end development and I'm trying to implement comment system for my Spring Web application. The catch here is that if a comment gets downvoted then comment owner's "karma" must be decremented as well.
Now, I had some experience with web development in PHP with some self-made spaghetti-coded frameworks, where one could implement the said logic with something like that:
class Comment {
function getUser() { return db_find("users", User::class, $this->columns->owner); }
function downvote() {
$user = $this->getUser();
$user->columns->karma--;
db_persist("users", $user);
}
}
JPA beans are made differently so I couldn't reapply the above solution to it, although my initial idea was pretty similar. I believe it is possible to achieve something like that by passing Session to the downvote method this way:
class Comment {
// ...
#ManyToOne
#JoinColumn(name = "owner_id")
var owner: User? = null
fun downvote(session: Session) {
this.rating -= 1;
this.owner.karma -= 1;
session.save(this.owner)
session.save(this)
}
}
But it seems really wrong and unnatural to me. I've also had an idea to put this logic in controller, but that one seems like a bad practice too...
So, I kinda have an entity (comment) that should modify another entity (user) on modification (call to downvote) and I'm not sure how to implement all this in JPA-like way.
First of all, you should separate the logic (e.g., transaction operations) from the entity.
The entity should be (more or less) a pojo, you create another class for those business logic implementations.
A typical architecture would be:
entities: pojos
dao or repositories: each repository usually talks (read/write) to one entity class
services (here you can modify as many entities as you need through required repositories)
A related group of applications I've been assigned share a database table for configuration values that has a table with columns 'application', 'config_name', 'config_type' (IE String, Integer), and 'config_value'. There's also a stored procedure that takes in a string (applicationName) and returns all config names, types, and values where applicationName == application.
In each application, a wrapper class is instantiated which contains a static ThreadLocal (hereafter 'static config)', and that static config pulls all values from the config table for the application.
When loading configuration values, the stored procedure returns a massive list of properties that are iterated over, going through a massive list of if-else statements testing whether the 'config_name' column matches a string literal, and if so, loads the value into a differently named variable.
EX:
if (result.isBeforeFirst()) {
while(result.next()) {
if (result.getString("config_name").equals("myConfig1") {
myConfigurationValue1 = result.getString(config_value); }
else if (result.getString("config_name").equals("myConfig2") {
myConfigurationValue2 = result.getString(config_value); }
}}
These cover between 60-100ish configs per app, and each application has an identical Configuration class save for the names of the properties they're trying to read.
So my questions are:
Having one gigantic configuration class is poor design, right? I'm not entirely sure how to break them down and I can't share them here, but I'm assuming best practice would be to have multiple configuration classes that have all the components needed to perform a particular operation, IE 'LocalDatabaseConfig' or '(ExternalSystemName)DatabaseConfig'?
Once broken down, what's the best way to get config valuee where needed without static access? If I have each class instantiate the configuration it needs I'll be doing a lot of redundant db operations, but if I just pass them from the application entry point then many classes have to 'hold on' to data they don't need to feed it to later classes... Is this a time when static config classes are the best option??
Is there an elegant way to load properties from the DB (in core java - company is very particular with third party libraries) without using this massive if-else chain I keep thinking that ideally we'd just dynamically load each property as it's referenced, but the only way I can think to do that is to use another stored procedure that takes in a unique identifier for a property and load it that way, but that would involve a lot more string literals...m
(Might be invalidated by 3) Is there a better way for the comparison in the pseudo-code above to test for a property rather than using a string literal? Could this be resolved if we just agreed to name our configuration properties in the application the same way they're named in the DB?
Currently every application just copy-pastes this configuration class and replaces the string literals and variable names; many of the values are unique in name and value, some are unique in value but are named the same between applications (and vice versa), and some are the same name and value for each application, but because the stored procedure fetches values based on application, redundant db entries are necessary (despite that many such values are supposed to be the same at all times, and any change to one needs to be performed on the other versions as well). Would it make sense to create a core library class that can construct any of the proposed 'broken down' configuration classes? IE, every application needs some basic logging configurations that don't change across the applications. We already have a core library that's a dependency for each application, but I don't know whether it would make sense add all/some/none of the configuration classes to the core library...
Thanks for your help! Sorry for the abundance of questions!?
The cascading if-then-else might be eliminated by using a while loop to copy the database-query results into two maps: a Map[String, String] for the string-based configuration variables, and a Map[String, Integer] for the integer configuration variables. Then the class could provide the following operations:
public String lookupStringVariable(String name, String defaultValue) {
String value = stringMap.get(name);
if (value == null) {
return defaultValue;
} else {
return value;
}
}
public int lookupIntVariable(String name, int defaultValue) {
Integer value = intMap.get(name);
if (value == null) {
return defaultValue;
} else {
return value.intValue();
}
}
If there is a requirement (perhaps for runtime performance) to have the configuration values stored in fields of the configuration class, then the configuration class could make the above two operations private and use them to initialize fields. For example:
logLevel = lookupIntVariable("log_level", 2);
logDir = lookupStringVariable("log_dir", "/tmp");
An alternative (but complementary) suggestion is to write a code generator application that will query the DB table and generate a separate Java class for each value in the application column of the DB table. The implementation of a generated Java class would use whatever coding approach you like to query the DB table and retrieve the application-specific configuration variables. Once you have written this generator application, you can rerun it whenever the DB table is updated to add/modify configuration variables. If you decide to write such a generator, you can use print() statements to generate the Java code. Alternatively, you might use a template engine to reduce some of the verbosity associated with print() statements. An example of a template engine is Velocity, but the Comparison of web template engines Wikipedia article lists dozens more.
You would be better off separating the database access from the application initialisation. A basic definition would be Map<String,String> returned by querying for one application's settings:
Map<String,String> config = dbOps.getConfig("myappname");
// which populates a map from the config_name/config_value queries:
// AS: config.put(result.getString("config_name"), result.getString("config_value");
Your application code then can initialise from the single application settings:
void init(Map<String,String> config) {
myConfigurationValue1 = config.get("myConfig1");
myConfigurationValue2 = config.get("myConfig2");
}
A benefit of this decoupling is that you define test cases for your application by hardwiring the config for different permutations of Map settings without accessing a huge test database configurations, and can test the config loader independently of your application logic.
Once this is working, you might consider whether dbOps.getConfig("myappname") caches the per-application settings to avoid excessive queries (if they don't change on database), or whether to declare Config as a class backed by Map but with calls for getInt / get and default values, and which throw RuntimeException if missing keys:
void init(Config config) {
myConfigurationValue1 = config.get("myConfig1", "aDefaultVal");
myConfigurationInt2 = config.getInt("myConfig2", 100);
}
The tutorial at https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-active-directory explains how to set up Spring Security with authentication at Microsoft Azure Active Directory.
Disregarding from two little differences (explained here OpenID Connect log in in with Office 365 and spring security ) this works fine.
In my application.properties there is this property:
azure.activedirectory.active-directory-groups=myADUserGroup
(Hint: azure.activedirectory.active-directory-groups seems to be the deprecated version of the newer azure.activedirectory.user-group.allowed-groups ...)
I don't want to limit on particular groups. Every user with a valid Microsoft account is OK for my use case.
Leaving the property blank or even deleting the property leads to this exception:
Caused by: java.lang.IllegalStateException: One of the User Group Properties must be populated. Please populate azure.activedirectory.user-group.allowed-groups
at com.microsoft.azure.spring.autoconfigure.aad.AADAuthenticationProperties.validateUserGroupProperties(AADAuthenticationProperties.java:148) ~[azure-spring-boot-2.3.1.jar:na]
A possible workaround is to enter some arbitrary group name for the property in application.properties:
azure.activedirectory.active-directory-groups=some-arbitrary-group-name-doesnt-matter
and just do not use #PreAuthorize("hasRole('[group / role name]')").
This works (as long as your app is not interested in the role names) but it does not feel correct.
A) Is there a "right" way to set a wildcard active-directory-group?
B) org.springframework.security.core.Authentication.getAuthorities() seems to deliver only those group names / role names that are entered in that property, so the workaround delivers none (but ROLE_USER). I want to read all the groups / roles at the user. So I ask a second question: How can I get all roles from org.springframework.security.core.Authentication.getAuthorities() without knowing all of them and especially without entering all of them into the "azure.activedirectory.active-directory-groups" property?
For now, it does not support to set a wildcard for azure active directory group.
You can give you voice to azure ad feedback and if others have same demand will voteup you. Much vote will promote this feature to be achieve.
It's not a group wildcard, but if stateless processing suits your need,
azure.activedirectory.active-directory-groups=...
may be replaced with
azure.activedirectory.session-stateless=true
This will activate AADAppRoleStatelessAuthenticationFilter instead of AADAuthenticationFilter, which doesn't require specifying groups via azure.activedirectory.active-directory-groups.
The roles you want to use have to declared in the application manifest
As there is no support for a wildcard for groups at the moment, I built a workaround by ignoring whether the user group is valid or not.
For this I made a copy of com.microsoft.azure.spring.autoconfigure.aad.AzureADGraphClient and commented out this code snippet:
.filter(this::isValidUserGroupToGrantAuthority)
and I made a copy of com.microsoft.azure.spring.autoconfigure.aad.AADOAuth2UserService with
graphClient = new MyAzureADGraphClient(...
instead of
graphClient = new AzureADGraphClient(...
And in the SecurityConfiguration I injected the AAD properties:
#Autowired(required = false) private AADAuthenticationProperties aadAuthenticationProperties;
#Autowired(required = false) private ServiceEndpointsProperties serviceEndpointsProps;
and called my own AADOAuth2UserService in void configure(HttpSecurity http):
EvaAADOAuth2UserService oidcUserService = new EvaAADOAuth2UserService(aadAuthenticationProperties, serviceEndpointsProps);
httpSecurity.oauth2Login().loginPage(LOGIN_URL).permitAll().userInfoEndpoint().oidcUserService(oidcUserService);
I like what Spring Data Rest provides out of the box but I see a few design problems that I'd like to address prior to using it for my next project:
SDR's main drift seems to be to expose data repositories straight out over MVC. I consider this to be a flawed approach because you end up tying your API to whatever your DB says. Consider this in your DB:
TABLE customer {
fullName TEXT
}
Under spring data rest that will end up being exported to for eg:
{
"fullname": "foo"
}
now suppose I decide to change my DB table to say:
TABLE customer {
firstName TEXT
lastName TEXT
}
that is, I split the field in two: suddenly my client-facing API has been modified. If I had better control I'd be delivering ApiCustomer object which contains:
ApiCustomer{
String fullname;
}
and during mapping I get the chance to say that fullName is now firstName + lastName leaving my customer-facing API unchanged. Is it possible for me to hook into a conversion process so as to make sure this doesn't occur?
Let's say I want to develop an N-tier application where I have an MVC module that handles all HTTP/REST/validation bits and a core module which has links to DB. The two modules live in different JVMs and are connected to each other with, for eg, rabbitmq or whatever.
Unless I'm missing something, Spring Data Rest wants me to place repositories in the MVC module where I do not have any database components at all. I cannot figure out a way to tell it: these are the repositories you will have somewhere else, whenever you need to do something on them, ask me first so I get a chance to proxy to the Core module.
Am I going down the wrong path here?
This new spring project seems to fit the bill very well for this:
http://docs.spring.io/spring-data/keyvalue/docs/current/reference/html/
I've followed through this sample code and tried to implement it with only simple JPA. However, when I tried to sign up with a Google account or login with an existing user account, it gave me this error.
[RuntimeException: No EntityManager bound to this thread. Try to annotate your action method with #play.db.jpa.Transactional]
private static List<User> getAuthUserFind(final AuthUserIdentity identity)
{
-> List<User> query = JPA.em().createQuery(
After googling for a while, many solutions suggest adding the #Transactional annotation to the calling play action, but that action is in the play-authenticate code.
Is there a solution for this issue, or do I have to use it with Ebeans?
I am using Play Framework 2.2.1 and implementing my program in Java.
It's not necessary to use Ebean,
I have used mybatis as persistence provider, but in order to save the user and login without problem you should use the same hashing algorithm.
the hashing algorithm is used to store the password.
to use your custom persistence provider like JPA or whatever you want, you should implement the Authentication Provider interfaces, see UsernamePasswordAuthProvider in the example project for more details.
Focus ,especially, on "signupUser" and "loginUser" methods.
I have modified play-authenticate to support Login/password instead of email/password identityId.
see Modified version of Play-Authenticate.
Cheers.
You could use JPA.withTransaction(callback). This is the better way when you can't put #Transactional in a method or you don't want to.
Cheers,
Alberto