How to implement security in spring boot if we use scopes with attributes - s4sdk

I use scopes with attributes as described here.
Do you know how to implement the security configuration in a spring boot app to achieve that only the corresponding data regarding the scope attribute will be served.

I think there are two approaches you can use to accomplish this result depending on your concrete requirements. However, first of all there is no such thing like a parametrized scope with XSUAA.
It is possible to model additional attributes into the role templates of XSUAA, for example, a Country attribute like this in xs-security.json
"attributes": [
{
"name" : "Country",
"description" : "Country parameter for the Role",
"valueType" : "string"
}],
"role-templates": [
{
"name": "BusinessPartnerViewer",
"description": "Role to view business addresses",
"scope-references" : [
"$XSAPPNAME.ViewAddresses"
],
"attribute-references": [
"Country"
]
}
Then you need to recreate your XSUAA instance in CloudFoundry with cf create-service xsuaa application <serviceinstance> -c xs-security.json. Note: You cannot update the binding when you had other role template definitions previously.
Based on this, a subscriber of the application may instantiate roles at runtime providing an attribute along with the OAuth scope.
This approach has the downside that the consumer of the application may have to create many roles depending on the possible permutations of scopes and attributes.
Of course, you can always consider implementing your own approach, if the first approach is not sufficient. In this case, your application has to model and resolve the dependencies yourself depending on the user context, i.e., you have to create a database table that maps users to scopes and/or additional attributes and then you lookup at runtime the properties based on the information from the Json Web Token.

Related

Relax Security for a Spring Data REST Projection

I have a User class and I want to authorize access such that only a user gets to see what he is entitled to.
This was easily achievable using Spring Security in conjunction with Spring Data Rest where in JPA Repository I did below -
public interface UserRepository extends JPARepository<User,Integer> {
#PreAuthorize("hasRole('LOGGED_IN') and principal.user.id == #id")
User findOne(#Param("id") Integer id);
}
In this way, a user when visits to Spring Data REST scaffolded URLs like -
/users/{id}
/users/{id}/userPosts
Only those logged in with {id} get to see these and everyone else gets 401 like I would have wanted.
My problem is that I have one of Projections which is a public view of each user and I am crating it using Spring Data Rest projections as below which I want to be accessible for every {id}
#Projection(name = "details", types = User.class)
public interface UserDetailsProjection {
..
}
So, /users/{id1}?projection=details as well as /users/{id2}?projection=details should give 200 OK and show data even though user is logged in by {id1}
I began implementing this by marking projection with #PreAuthorize("permitAll") but that won't work since Repository has harder security check. Can we have this functionality where for a projection we can relax security ?
I am using latest Spring Data Rest and Spring Security distributions
Seems reasonable to add a custom controller for this use-case.
Please also consider:
Evaluate access in projections using #Value annotations
Add another entity for the same database data but with different field set for read-only operations, e.g. using inheritance (be careful with caching, etc.) - depends on your data storage type
Modify model to split User entity into two different entities (profile, account) since they seem to have different access and possibly even operations
You can also add a ResourceProcessor<UserSummaryProjection> to evaluate access programmatically and replace resource content (projection) with a DTO
Example of evaluating access in projections with #Value annotations:
#Projection(types = User.class, name = "summary")
public interface UserSummaryProjection {
#Value("#{#userSecurity.canReadEmail(target) ? target.email: null}")
String getEmail();
}
Added spring security code in the data access layer is not a good idea. I would suggest you to add the #PreAuthorize annotation to the controller/service method. Since you have a query parameter, ?projection=details, you can have separate controller/service method for the details projection.
Add following to your details projection method:
#RequestMapping("/url", params = {"projection"})
#PreAuthorize("hasRole('LOGGED_IN') and principal.user.id == #id")

How to handle authorization with Breeze JS?

Currently my app looks at router parameter and logged in user (Principal.Identity) to authorize access to certain resources (e.g: Add student to your class [identity + class id]). However, If I'm not wrong, breeze js support just one bulk save. It seems to be that I will have to open each and every data and run through the validation/authorization. That is fine,
but what I may lose is nice separation of cross cutting concern out side my business logic (as a message handler) (finding what roles user has on the class) and nice Authroize annotation feature (just say what roles are needed). So do I have to trade off or is there better programming model which Breeze JS might suggest?
Update:
My question is more on how to separate the authorization (find assigned roles in message handler + verify if required roles are present by adding authorize attribute to controller methods) logic from business or data access logic. Without breeze, I will inspect the incoming message and its route parameter to fetch all its roles then in my put/post/delete methods I would annotate with required roles. I cannot use this technique with breeze (its not breeze's limitation, its trade off when you go for bulk save). So wanted to know if there is any programming model or design pattern already used by breeze guys. There is something on breeze's samples which is overriding context and using repository pattern, will follow that for now.
Breeze can have as many 'save' endpoints as you want. For example, a hypothetical server implementation might be
[BreezeController]
public class MyController : ApiController {
[HttpPost]
[Authorize(...)]
public SaveResult SaveCustomersAndOrders(JObject saveBundle) {
// CheckCustomersAndOrders would be a custom method that validates your data
ContextProvider.BeforeSaveEntitiesDelegate = CheckCustomerAndOrders;
return ContextProvider.SaveChanges(saveBundle);
}
[HttpPost]
[Authorize]
public SaveResult SaveSuppliersAndProducts(JObject saveBundle) {
...
}
You would call these endpoints like this
var so = new SaveOptions({ resourceName: "SaveWithFreight2", tag: "freight update" });
myEntityManager.saveChanges(customerAndOrderEntities, {
resourceName: "SaveCustomersAndOrder" }
).then(...)
or
myEntityManager.saveChanges(supplierAndProductEntities, {
resourceName: "SaveSuppliersAndProducts" }
).then(...)
Authorization is mediated via the [Authorize] attribute on each of the [HttpPost] methods. You can read more about the [Authorize] attribute here:
http://sixgun.wordpress.com/2012/02/29/asp-net-web-api-basic-authentication/
The proper way to do this IMHO is to separate the endpoint authorization and the database actions authorization.
First, create an entity that manages the grands per controller/method and role. For each method you have a value allowed - not allowed for the specific role. You create a special attribute (subclass of Authorize) that you apply to your controllers (breeze or plain web api) that reads the data and decides whether the specific endpoint can be called for the user/role. Otherwise it throws the Unauthorized exception.
On the breeze side (client) you extend the default adapter settings with a method that adds the authentication headers from identity that you received at login, something like this :
var origAjaxCtor = breeze.config.getAdapterInstance('ajax');
$.extend(true, origAjaxCtor.defaultSettings, Security.getAuthenticationHeaders());
On the server, add a second entity that manages the authorization for the CRUD operations. You need a table like (EntityName, AllowInsert, AllowUpdate, AllowDelete). Add a BeforeSave event on the Context Manager or on the ORM (EF or something else) that loops all entities and applies the policy specified on the table above.
This way you have a clear separation of the endpoint logic from the backend CRUD logic.
In all cases the authorization logic should first be implemented server side and if needed should be pushed to the clients.
The way breeze is implemented and with the above design you should not need more than 1 save endpoint.
Hope it helps.
However, If I'm not wrong, breeze js support just one bulk save.
That is entirely wrong. You have free reign to create your own save methods. Read the docs, it's all there.

Keep record of what users do in Spring MVC

I have a very large application written in Spring MVC. I want to keep an "activity record" that tracks into a database what users do in my application.
In the first stage I just want an activity log, it can be just a list of the controller methods that get called during user's actions, but later on I would like this info to be more "human readable", i.e. instead of "modifyAccount(accountId = 5, accountBalance =500) something like "user X updates balance for account 5 to 500".
The problem I see is, since my application is very large, I would not like to modify each of my actions to add this logging mechanism. Is there a more flexible, declarative way to do this?
You can make use of Aspect Oriented Programming (AOP) to automate the logging.
http://static.springsource.org/spring/docs/2.0.8/reference/aop.html
In the above page shows many examples on how to use AOP with spring. One example is the use of annotations to find methods you're interested in. The use of such annotation is an easy way to determine what methods should be logged.
The #Audit annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Auditable {
...
}
The auditing method
#After("#annotation(auditable)", argNames="joinPoint")
public void audit(JoinPoint joinPoint) {
logger.info("Called {} with arguments {}",
joinPoint.getSignature().getLongString(), joinPoint.getArgs());
}
I did not test this code but it gets the point across.

Exposing entities through services and partial responses

What do you think about exposing domain entities through services? I tried it in an application, but I came to the conclusion that exposing domain model to the client is not such a good idea.
Advantages:
Really easy to transport data from-to client
List item
(De)Serialization is really easy: just put jackson in the classpath and it will handle it. No extra logic is needed.
No need to duplicate entities POJOs. At least in early stages, the API resources will be pretty much the same as the domain model.
Disadvantages:
The API's get very tightly coupled to the model and you can't change the model without affecting the API
Partial responses. There are cases where you don't want to return all the fields of the entities, just some of them. How do you accomplish it?
So, let's take the following REST example. The following API declares that GET on the user resource returns the following information.
GET
/users/12
{
"firstName":"John",
"lastName":"Poe"
"address":"my street"
}
Usually, I would create a User entity, a user service to return the user and a REST controller to serve the request like this:
#RequestMapping("/users/{id}")
public #ResponseBody User getUser(#PathVariable Long id) {
return userService.findById(id);
}
Should I avoid returning the User entity?
If yes, should I create another class and handle myself the mapping between this class and the entity?
Is there a pattern for this?
How to accomplish partial expansion? (i.e. return only the firstName and lastName for the user)
P.S: using #JSONFilter and ObjectMapper to accomplish partial responses seems too heavyweight to me because you loose the beauty of spring data

Multi-tenancy with MVC3 and Custom Membership Provider

I have a question regarding Multi-tenancy (with MVC3, EF) and a custom SQL Membership provider.
I have custom User and Roles membership classes created, since I have to include the userId in my application tables along with additional user based attributes. I am now converting this into a multi-tenancy application. We are going for a shared-db, shared-app model. We have a master Tenant table that stores the tenant details (including URL ) and the Tenant_id has been included in every table. And now we're working on the changes to the application itself.
The assumption is that tenants will login using a URL like so: tenantUrl.mybaseURL.com.
I am going to change my custom User Validate methods as per this algorithm:
- User goes to URL to login
- The Account controller logon method calls the Custom validate method passing in user/pwd and the tenantId (which has been looked up from the db using the URL).
- The custom validate method checks if the user/password/tenantId combination are valid.
- If valid, we set the tenant Id in a HttpRequest Object and login the user
- For each db access, we lookup the Request object for the tenandId and use that as a filter.
Edit: This is my TenantContext class, where I will be setting/getting the tenantId
public class TenantContext
{
public static int TenantId
{
set
{
if (!HttpContext.Current.Items.Contains("tenant-code"))
HttpContext.Current.Items.Add("tenant-code", value);
HttpContext.Current.Items["tenant-code"] = value;
}
get {return HttpContext.Current.Items.Contains("tenant-code") ? Convert.ToInt32(HttpContext.Current.Items["tenant-code"]) : -1; }
}
}
The tenantId will be set in the Account Controller Login in the above Context.
Is the above a good way to do this or is there a better way? Anybody see any issues with this I should be aware of?
I have seen an example of the tenantId being stored in AppSettings here Handling data access in multi tenant site. Is this a better way to do it?
Thank You
Your algorithm is perfect and in fact i have been working in this kind of an implementation. I have a suggestion that for you, that you use the custom object to maintain the useridentity across different layers. This will contain the userid, tenantid etc.. as this HttpContext will not be helping you in the case of a WCF service and in the context of a user belonging to a tenant and operating on behalf of another tenant. Hence, it would be a better option to have a UserIdentity object that identifies the user. Also, do send the tenantids to the data access layers and do not infer the tenant id's from the request as it will not be available in all environments.

Resources