Grails check role access for specific controller action - spring

I need to display/hide action buttons depending if the user can access (by role definition) the specific controller/action. I'm using Spring Security plugin.
My goal is to used the annotation #Secured("ROLE_...") for every method of each of my controller and I'm looking for a way to check, before calling the action, if the user has access to this specific action. I'm guessing there is way to check this because the annotation brings the information but I cannot find any solution.
In this example I'm trying to find the HASACCESS method:
The controller with the #Secured annotation
class MyExampleController{
#Secured("ROLE_ADMIN")
def myMethod(){ do stuff.. }
}
The HTML code to include de link
<role:link controller="myExample" action="myMethod">Action</role:link>
And my tagLib role
class RoleTagLib {
static namespace = "role"
def link = {attrs, body ->
User user = (User) springSecurityService.currentUser
if(HASACCESS(user, attrs.controller, attrs.action)){
out << g.link(attrs, body)
}
}
}
I found in this thread the "hasAccess()" method contained into the SecurityTagLib but this method is protected and even when I extend the SecurityTagLib with mine the call of this method returns me "No signature of method...". I think it uses the interceptUrlMap defined in Config.groovy and not the annotations anyway.
EDIT: I succeed to extend the security tagLib and use the "hasAccess" method but it seems that it uses only the interceptUrlMap contained in Config.groovy and doesn't care about the annotations I put in my controllers.

Use
<sec:ifAllGranted roles="ROLE_ADMIN,ROLE_SUPERVISOR">
secure stuff here
</sec:ifAllGranted>
or
<sec:ifAnyGranted roles="ROLE_ADMIN,ROLE_SUPERVISOR">
secure stuff here
</sec:ifAnyGranted>
according the Spring Security Core Grails plugin documentation.
Or simply use the Spring security core taglib with your tag library.
class RoleTagLib {
static namespace = "role"
SpringSecurityService springSecurityService
def link = { attrs, body ->
User user = (User) springSecurityService.currentUser
sec.ifAnyGranted(roles: 'ROLE_ADMIN,ROLE_SUPERVISOR'){
out << g.link(attrs, body)
}
}
}

Ok I found a solution. The method "hasAccess" in SecurityTagLib is based on grails.plugins.springsecurity.securityConfigType in Config.groovy. My initial value was SecurityConfigType.InterceptUrlMap and then I would have defined every url accessible and specify which role can access each of them manually in the grails.plugins.springsecurity.interceptUrlMap
The solution is to change this to SecurityConfigType.Annotation and modify interceptUrlMap to staticRules. Then the method "hasAccess" is based on the annotations defined in the controller and can hide properly the content with my tagLib wrapped from SecurityTagLib.
There is the code in Config.groovy
grails.plugins.springsecurity.securityConfigType = SecurityConfigType.Annotation
grails.plugins.springsecurity.staticRules = [
... your rules ... for example:
'/**': ['ROLE_ADMIN_ACCESS']
]
The code of my tagLib
class RoleTagLib extends SecurityTagLib {
static namespace = "role"
def link = { attrs, body ->
if (hasAccess(attrs.clone(), "link")) {
out << g.link(attrs, body)
}
}
}
And I use this to show or hide any link in my .gsp files based on the #Secured annotation put for every action of every controller
<role:link controller="myController" action="myAction">
Action
</role:link>

This is for Grails 2.3
To check action access from another controller or service, do this:
#Secured(["ONE_OF_MY_ROLES"])
class SomeController {
SecurityTagLib securityTagLib = (SecurityTagLib)Holders.grailsApplication.mainContext.getBean('grails.plugins.springsecurity.SecurityTagLib')
def show() {
def access = securityTagLib.hasAccess([controller: 'product', action: 'show'], 'access')
}
}

Related

How to just get the data using CRUD POST method?

I have developed Small Spring boot Rest api app. I can able to get the data or create new record and search with paging and sorting.
Now i'm looking for provide input data in body to get the data instead of providing in URL with GET method. Is this method also default function ? Please advise.
public interface CodeTextRepository extends PagingAndSortingRepository<CodeText, Long> {
}
How to write POST method to just get the data ?
http://localhost:8080/api/code
method : POST
{
"code":1
}
If I understand you correctly, you want to create a controller that will get the a model as body parameter ({ "code": 1 }) in a POST method and then do something with it.
To do that, you can create a controller that looks like the following (I inserted pseudo-code as an example):
#RestController
#RequestMapping(value = "/api/code")
public class CodeTextController {
private CodeTextRepository codeTextRepository;
// constructor injection
public CodeTextController(CodeTextRepository codeTextRepository) {
this.codeTextRepository = codeTextRepository;
}
#PostMapping
public CodeText postCodeText(#RequestBody CodeTextRequest codeTextRequest) {
// some code to get from the DB
return codeText;
}
}
public class CodeTextRequest {
private int code;
// getters and setters
}
Simply add Accept header to the request, like
accept: application/json
Spring Data-Rest will return the body after a POST request if either the returnBodyOnCreate flag was explicitly set to true in the RepositoryRestConfiguration OR if the flag was NOT set AND the request has an Accept header.
You can set the flag directly during configuration, or you can set it via the application.properties:
spring.data.rest.returnBodyOnCreate = true
you can also set it separately for update:
spring.data.rest.returnBodyOnUpdate = true
---- edit
Maybe I misunderstood your question. If you simply want to GET an existing data using POST method, then DO NOT DO IT AT ALL! That's not a REST API any more. There must be some reason you want to do it, but you should try do resolve that original problem instead in another way!

Validating RESTful URLs for every request the DRY way

Our Grails 2.4.4 application is using RESTful URLs throughout. Given the following URL:
/stores/123/products/456
I'd like to validate that there is a store with an ID of 123, and if not, redirect to a 404 on every request to the Product controller. I don't want to have to put that store lookup code in each action method, nor do I want to create a controller base class, because then I have to put a method call in every action method.
Can this be done with a interceptor somehow?
Interceptors are introduced in Grails 3.0. You would need filters in Grails 2.4.4.
before = { } is what will be needed here.
Also look at the docs which variable are available to filters by default (eg: params, request, response etc). If this is still unclear, I can add an answer as an example. But I hope docs will be self explanatory. As an example i would do it as
class EntityCheckFilters {
def filters = {
storeExistCheck( controller:'product' ) {
before = {
if ( !params.storeId || !Store.exists( params.sotreId as Long ) ) {
response.sendError(404)
// or for example if you have a separate action to handle 404
// redirect(action: 'handle404')
// this is important,
// because we do not want to pass through with the original call
return false
}
}
}
}
}
I think you can do this using:
URL Mapping
Filters
But I dont think putting a logic (checking if there is a valid store with the given id) in URL Mapping is good idea, so better to use Filters.
So you url mapping will look like this:
"/stores/$storeId/products/$productId" (controller = "product")
And your filter:
class YourFilterNameFilters {
def filters = {
secureReports(controller:'*', action:'*') {
before = {
if(parmas.controller == "product" && params.storeId){
Store store = Store.get(params.sotreId)
if(!store){
response.sendError(404)
}
}
}
}
}

Grails + RESTful URL mapping + Filters + Routes

Member have many jobs. A member can add, delete or update Jobs. Currently there are actions (add, delete or update) defined in a controller which are called through jQuery.ajax(). We are sending job id and member id to perform the operation. Member id is necessary because there is a role admin who can modify the job on behalf of members, so we need to identify the member. But sending member id is dangerous as anyone can send the request by modifying the member id.
I know, we can add constraint do restrict that only admin can modify the jobs or a member can modify only his jobs. My question is, Do I need to add these constraints in the action of the controller or Is there any Grails way to do that. I have google, the same thing is handled in Ruby and Rails by using routes. And in grails I have skim through RESTful URL mapping, which is perhaps used for this purpose.
Can anyone points me to right direction, thanks. I am using Grails 2.1.1.
You can implement some realization of AbstractPersistenceEventListenerService to not allow perform actions with entity that constains id of not logged in user. Example:
class MultiTenantPersistenceEventListenerService extends AbstractPersistenceEventListenerService {
def springSecurityService
#Override
protected AbstractPersistenceEventListener createPersistenceEventListener(Datastore datastore) {
return new MultiTenantPersistenceEventListener(datastore)
}
}
class MultiTenantPersistenceEventListener extends AbstractPersistenceEventListener {
MultiTenantPersistenceEventListener(final Datastore datastore) {
super(datastore)
}
#Override
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
def entity = event.getEntityObject() // could be your Job domain entity
def user = springSecurityService.getCurrentUser() //current logged in user
if(entity.hasProperty('userId')){ // every job belongs to User
if(entity.userId != user.id){
throw new AccessDeniedException("Acces Denied !")
}
}
}
}
I'd recomment to use grails spring-security-plugin. There is a lot of information in web about plugin and it's easy configurable. Plugin allows you to perfrom controller's action in secure way. For example:
#Secured(['ROLE_USER'])
def followAjax = { ... }
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
def personal = { ... }
For more information - plugin and spring-security with grails.
You can use Authorize attribute to authorize the user,
e.g
[CustomAuthorize(Roles=SiteRoles.Admin|SiteRoles.HelpDesk)]
public ActionResult Index()
{
return View();
}
This is a nice approach for making website secure.
go through these link, this will help you.
custom authorization with asp.net mvc
asp.net mvc authorization

how to use session in grails

I am new to grails. And I have to work with session. I have seen the session documentation. But no idea where to put the code in my controller. I have a page for student creation names createStudent. Now I want that this page only be access able when the user will be in session. Now how can I do it. Should I have to set the user in a variable at the time of login. Can anyone please help me on this ?
def index() {
def user = session["user"]
if (user){
redirect(controller: 'admistratorAction', action: 'createUser')
}else{
redirect(controller: 'login', action: 'index')
}
}
You could use the session.getAttribute(key) and session.setAttribute(key, value) methods inside your controller. Alternatively, there are plugins such as the Spring Security Core Plugin that already handle this very well.
There's a good tutorial by Peter Ledbrook for the Spring Security plugin here and the plugin documentation links to at least one other tutorial.
** Edit **
As you suggested, in order to use the session directly the user would need to be set in the session at an earlier point. For example:
def setCurrentStudent() {
def aStudent = [name: "Student1"]
session["user"] = aStudent
render "Added $aStudent to the session."
}
Spring Security will do this automatically at login. Then, the current user can then be accessed at any time using the springSecurityService.
class SomeController {
def springSecurityService
def someAction = {
def user = springSecurityService.currentUser
…
}
}

Generating url for a resource in asp.net web api outside of ApiController

Looking for a way to construct or generate a url for a specific resource in asp.net web api. It can be done in the controller since it inherits from ApiController hence you get the UrlHelper.
I am looking to construct resource url out of the context of the ApiController.
Here is what I did:
Requires HttpContext/Request, so might not work in Application_Start.
Only tested in WebApi 1
Only works for routes registered in GlobalConfiguration (but if you have some other one, just pass it in instead)
// given HttpContext context, e.g. HttpContext.Current
var request = new HttpRequestMessage(HttpMethod.Get, context.Request.Url) {
Properties = {
{ HttpPropertyKeys.HttpConfigurationKey, GlobalConfiguration.Configuration },
{ HttpPropertyKeys.HttpRouteDataKey, new HttpRouteData(new HttpRoute()) },
{ "MS_HttpContext", new HttpContextWrapper(context) }
}
};
var urlHelper = new UrlHelper(request);
What about the UrlHelper classes:
System.Web.Http.Routing.UrlHelper;
System.Web.Mvc.UrlHelper
The MVC one has some useful static methods accepting routing information or it can be used as an instance created by passing in a RequestContext (which is available in most MVC filters and various other places). The instance methods should be exactly what you need to generate urls.
The HTTP one accepts a ControllerContext (which is also available in most HTTP filters and various other places).
I'm not sure about the ApiController, as I haven't used it before. This may then be redundant for you, but then again, it may not be. Check out your Global.asax.cs file, specifically the RegisterRoutes function. Initially, you should see the following mapping:
routes.MapRoute ("Default", "{controller}/{action}/{id}", new { controller = "MyController", action = "Index", id = "" });
So by default your application is set up to handle routes in the following format:
{ControllerName}/{ActionName}/{ResourceId}
A controller class set up like the following should enable you to receive requests in that format.
class {ControllerName}Controller : ApiController
{
public ActionResult {ActionName} (string id)
{
// fetch your resource by its unique identifier
}
}

Resources