GORM get domain object list by property - grails

I'm trying to get a list of domain objects back, but only those that the user is allowed to see. This is based on what granted role that user has from spring security.
What I'd like to be able to do in my controller is something along the lines of
[reportInstanceList: Report.list(params).sort{it.name}]
but only get the reports where
Report.role = SecurityContextHolder.getContext().getAuthentication().getAuthorities()
I have the Spring security stuff in another service class, but for simplicity's sake, its inline here.
Is there a way to direct GORM to only pull the records where the roles match?

Something like:
def reports = Report.createCriteria().list( params ) {
'in'( "role", SpringSecurityUtils.principalAuthorities )
}
[ reportInstanceList: reports, totalCount: reports.totalCount ]
Should work...

This is what dynamic finders are for. You can use the findAllBy finder to get all the objects with an attribute.
Report.findAllByRoleInList(SecurityContextHolder.getContext().getAuthentication().getAuthorities())
You can also sort at the db level by passing a map of params.
Report.findAllByRoleInList(roles, [sort: 'name'])

Related

Grails secure URL's using get form search

I have a Grails application using Spring Security.
This application is basically a content management system, so it is a CRUD.
My URL's access are basically formatted as follows:
/$controller/$action/$id
This is where encounters problems. That occurs in a controller, for example, to change a user I have the following URL:
/user/update/1
And into the controller I have the following code:
def update(Long id) {
def user = User.get(id);
[user: user]
}
That's the problem. If the user change the (id) directly without checking if the user id in request is correct, anyone can surf the users of my system. Now i have a big problem.
The solution that I thought would be to create a unique hash for each registration system, which would hinder the user to understand that, for example, the ID 1 has the hash 123aabbCCDD, for example.
But i have a lot of registers and many domains in the system, and i don't know if this is the best solution.
I need help to know, for example, using the spring security, I can do this kind of thing.
I tried to find solutions to the issue but I'm not sure by what words to search, so if there is already a question like mine, put the link in comments please.
Thanks.
As Joshua points out, if this is a general problem where you need to limit which users (or which roles) can perform particular actions, the spring-security-acl plugin will help. But that can be tedious to work with because you typically need to model things in a fine-grained way, and you end up with a lot of ACL data in the db.
But if you only want to restrict users to being able to edit themselves, just don't pass the user id. You already know who the user is if the action requires authentication. If that's the case, change the action to something like
def springSecurityService
def update() {
[user: springSecurityService.currentUser]
}
A related workflow that can often avoid using ACLs is allowing a user to edit something that they own, e.g. a CreditCard. Assuming you have static hasMany = [creditCards: CreditCard] in the User class and static belongsTo = [user: User] (or just User user), then you can allow the form to send the credit card id, but you just need to use a modified query, e.g.
def springSecurityService
def update(Long id) {
def user = springSecurityService.currentUser
def card = CreditCard.findByIdAndUser(id, user)
[creditCard: card]
}
The final SQL query will look something like select ... from credit_card where id=? and user_id=?, which has a big security advantage over the SQL for a get() call which would be select ... from credit_card where id=?. A malicious user can still try to send any id they want, but since the where clause checks both the id and the user foreign key, if they're not logged in as the card owner, the finder will return null and you can treat that as a mistake or a hack and not allow access.
Note that the hash approach you described isn't very secure - it's just "security by obscurity". If each user's hash is constant, it's not difficult to find out what a user's hash is and forge a request (e.g. a coworker can just look at another's monitor and see the url in their browser).

Grails - the use of service layer

I have problems in organizing my code when I want to update a non-simple domain object. The problem is to separate responsibilities for the controller and the service layer.
More explicitly, assume that we have a domain class Client that depends on other domain classes like Address and so on.
In the view there is a gsp for editing some of the Clients properties including some of the nested properties like street on the Address.
When I would like to update those fields I call the update method on a Controller (in this case the ClientController).
I like the feature coming from the errors of a domain class when validated. Like if I in the Controller write
Client client = Client.get(params.id)
client.properties = params
client.validate()
If the client now has errors it is very easy to display them in the edit view.
But, I thought that updating, saving and getting the client from the database (Client.get(theId)) should be handled by the service layer. In my case I have to update or create other domain objects (like the Address) before I update the Client.
So one of my questions are how should the API look like for the service layer?
public ... updateClient(…)
In the literature they have the trivial example of updating the age of a person. So, their API consists of the id of the person and the new age. But, in my case I have about ten params from the view and they are just a subset of all properties of a client and I don't know which one of these that have changed.
I would like to have a Client in the controller that I can validate and resend to the edit view if it has validation errors.
I would like to handle the database interactions and transactions from the service layer.
How can I combine these? What responsibilities should the different layers have regarding update? How should the API of the service layer look like regarding update?
If there is a good reference implementation somewhere I would be happy to study it. Many times the service layer is unfortunately totally or partially ignored.
The missing piece of this puzzle is command objects. These classes represent the contract for your API into your services and provide you the ability to have a concrete class for your views and for validation. Let's look at an example.
Given a domain class of Client which as an Address and several Phone instances your Service layer might look like this:
...
class ClientService {
def updateClient(ClientUpdateCommand cmd) {
..
}
}
...
While the ClientUpdateCommand looks something like this:
#grails.validation.Validateable
class ClientUpdateCommand {
Long id
String name
List<PhoneUpdateCommand> phoneNumbers = []
AddressUpdateCommand address = new AddressUpdateCommand()
...
static constraints {
id(nullable: false)
name(nullable: false, blank: false, size:1..50)
...
}
...
}
You will note that this command object is composed of other command objects, and has constraints for validation. It may seem like you are replicating your domain classes here, but I have found that the more complex your application then more differences will appear between the domain classes and your command objects.
Next up is the use of the command object within your controller and your views. A controller method may look something like this:
Class ClientController {
...
def clientService
...
def edit(ClientUpdateCommand cmd) {
...
cmd = clientService.load(cmd.id)
Map model = [client: cmd]
render(view: 'edit', model: model)
}
def update(ClientUpdateCommand cmd) {
Map model = [client: cmd]
if (cmd.hasErrors() {
render(view: 'edit', model: model]
return
} else {
clientService.update(cmd)
...
}
...
}
}
I have left a lot out of the controller as I didn't want to bore you with the details but rather show how a command object replaces the domain instance. In some ways it's a little bit more work but it moves you completely away from manipulating the domain classes and delegates that to the service you have created. You will also notice that the command object replaces the domain class instance for your model for your views. I won't bother giving you any examples of the GSPs since they really don't change much when using command objects like this.
I'm sure there could be entire chapters of books written on the subject, but hopefully this gives you some insight and you can see that the answer to your question(s) is: Command objects.

Grails Session scope for service not working as expected

I'm making a web app that stores reports of various types as domain objects, so I have a domain object HeadOfHousehold which contains name data, and references to other domain objects such as the reports, addresses, and any dependants. I am trying to build a list of recently viewed/created HeadOfHousehold objects. After multiple Google searches, and scouring the manual, it appeared that a service would be an appropriate solution. So I created ClientListService:
#Transactional
class ClientListService {
static scope = "session"
String message // right now I'll be happy to just see the same message across
// pages I can add a list and manipulate it later.
}
I thought I could then reference it in my various controllers, and it would persist Something like this:
def clientListService
def index(){
hasSearched = false
clientListService = new ClientListService(message: "Hello")
[errorMessage: params.errorMessage, clients:clientListService]
}
Which should be available in a later controller:
class HeadOfHouseHoldController {
def clientListService
def index() {
[customer: HeadOfHousehold.get(params.id), clients: clientListService]
}//...
However when I try to get the message, it appears as if the object is null.
From my index.gsp:
***************${clients?.message}********************
So I don't know if I am not defining session properly (I'm not doing anything special to do so), if I'm misunderstanding how the session scope works, or something else. I do see the proper message on the original page which has defined the object, however I don't see it on any subsequent pages.
Also, I'm not sure if this is the proper way to go about this; right now all I really need is the list of HeadOfHouseholds that I would need (so I can add to the list from other pages), however I can see possibly adding other logic and items into such a class.
I think you understood the session scope correctly. Each Spring bean with a session scope is bound to the HTTP session.
But your first controller listing does it all wrong. You are not supposed to instantiate the service class yourself. This is what Spring (Grails) does.
class FooController {
def clientListService // gets autowired by Grails/Spring
def index(){
hasSearched = false
clientListService.message = 'Hello' // only assign a String value to the service
[errorMessage: params.errorMessage, clients:clientListService]
}
}
This means you cannot not do something like
clientListService = new ClientListService(message: "Hello")
and expect your code to work. Hope this helps.

Grails: find by one-to-many association with String

I have a following domain class:
class User {
static hasMany = [roles:String]
}
I would like to find every user which has role ROLE_ADMIN. Is there any possibility to do that with dynamic finders? user.findAllByRoles('ROLE_ADMIN') seems to give me an error.
UPDATE: it is quite easy to query association where Class A has a list of class B instances and both A and B are domain classes. But here class A is a domain class and class B is a simple Java string.
The code for querying association containing list of another domain objects would look like this:
`User.findAll { roles { role_name=='ROLE_ADMIN' } }`
What i am looking for is a way to specify the value of a String, for example:
`User.findAll { roles {THIS_VALUE=='ROLE_ADMIN' }}`
UPDATE 2: as far as i have found it is not possible to use criteria with collections of primitive types. It is possible to use HQL though:
User.findAll("from User a where :roles in elements(roles)",[roles:'ROLE_ADMIN'])
However it is not as usefull as a findAll or where query. I cannot chain findAll methods so defining other methods that for example: get ROLE_ADMIN users with username like 'xxx' requires rewriting whole HQL query. Maybe it is possible to express above HQL condition in form of a where expression?
Maybe you can do something like:
if you have already a user list (userList)
def list = userList.findAll { user -> user.roles =~ 'ROLE_ADMIN' }
Hope this help!
I have the same problem How to find records by value in their association property via DetachedCriteria
I made some investigation and, as I found, it's impossible.
The GORM DSL itself doesn't have any method to check that value contains in association.
It conains oly that criterias that are in SQL: AND, OR, IN.
But! You can join association as table in criteria Querying by Association Redux

symfony 1.4 - inject current logged in user into Doctrine model

I would like to inject, with full testability, the id of the current logged in user into a creator_id field of a Doctrine_Record class, without using the sfContext singleton. I found a couple of Doctrine behaviours like http://www.symfony-project.org/plugins/sfDoctrineActAsSignablePlugin, but they access the sfContext singleton in a listener or (in another example I found) in the save method of a subclass of Doctrine_Record.
I want to find a single entry point in the symfony controller, where I can inject the current logged in user and keep it till the end of the request.
How do I do?
Hope I have been clear enough.
EDIT:
As #jeremy suggested, I made a custom filter:
class userFilter extends sfFilter
{
public function execute($filterChain)
{
$user = $this->getContext()->getUser();
if ($user->isAuthenticated()) {
$guard = $user->getGuardUser();
Doctrine_Manager::getInstance()->setAttribute('logged_in_user', $guard->getId());
}
// Execute next filter
$filterChain->execute();
}
}
So now my tests and my tasks are sfContext free, I just have to set the proper user Id at some point before starting the interactions with the db:
Doctrine_Manager::getInstance()->setAttribute('logged_in_user', sfConfig::get('default_user'));
Great question! The use of sfContext everywhere is one of the uglier aspects of Symfony 1 and setting it on Doctrine_Manager sounds like a solid idea.
It's probably best to do this either in the configureDoctrine callback that happens in ProjectConfiguration (see below). I'm not 100% a user is present at this point, if it's not, your best bet is a custom filter (reference).
public function configureDoctrine(Doctrine_Manager $manager)
{
$manager->setParam('user_id', sfContext::getInstance()->getUser()->getGuardUser()->getId());
}
Thanks for raising this question. I wrote the http://www.symfony-project.org/plugins/sfAuditablePlugin with this in mind. I basically externalized the method that returns the userId so you can get the userId from session, doctrine parameter or wherever you have it.
Here are the settings to configure the method that returns an array containing user_id and user_name
# Retrieve User Array from custom implementation
# [0] => (int)user_id; [1] => (string)user_name;
getUserArray:
class_name: Utility
static_method_name: getUserAuditArray

Resources