Override Grails scaffolding URLs entirely or with prefix - grails

I have a controller that has static scaffold = true defined, as well as some custom actions.
I would like to ensure that only logged-in users and those of type ADMIN (some Enum value in our domain) can access it. To achieve this I've implemented a grails filter that is mapped to the /admin/** URI space, but of course the URIs for the Domain/Controller in question when scaffolding are not under there. I have added custom, named, URL mappings for the show/edit/create actions (which work and delegate straight to the scaffold layer), but I end up with two URI contexts dedicated to this purpose.
I would prefer being able to say to the scaffolded controller "Use this URI as a prefix for all your URIs" and be done with it, but searching the docs and web in general have not proven very helpful.
Any ideas?

Scaffolded controllers generate all their URLs using the standard taglib calls, which are sensitive to URL mappings. So if you have the URL mappings right then it should just work. If you have a MyDomainController that you want to be mapped under /admin then you need something like
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?" {
constraints {
controller(validator:{
// make sure this mapping doesn't apply to the MyDomainController,
// so it will only be accessible via the protected /admin URL
return it != "myDomain"
})
}
}
// special rule for the MyDomainController
"/admin/myDomain/$action?/$id?"(controller:"myDomain")
}
}
You can use any of the usual Grails constraint types on a URL mapping, so you could restrict by whitelist
controller(inList:['foo', 'bar'])
or by regular expression
// exclude all controllers whose name starts "sec", e.g. secUser, secRole, ...
controller(matches:/(?!sec).*/)

Related

Conditional namespaces in mvc views

I'm working on MVC 3 and using resource files to localize the application. Now we have another customer on board for the application and they would like to change some of the text on the application..typical.
I have create a separated resource file for them and would like to do something like this in views
if (customer =A )
#using Resources.customerA
else
#using Resources.customerB
I've a resource class in both namespaces so something like this works fine if I change the namespace
Resource.WelcomeUser
Is it possible to use conditional using statement in views? I'm unable to find the right syntax for this. Any ideas?
You can put both using statements in View, but when you use classes you would have to write some namespace prefix.
Example:
#using Project.Resources.customerA
#using Project.Resources.customerB
using classes:
customerA.WelcomeUser
customerB.WelcomeUser
I think there is no other way, because two files cannot have the same path.
What you're really talking about is the provider pattern. You have two (or more) interchangeable things, and you want to be able to use one or the other contextually.
The correct way to do this in an OO context is to create and use an interface, while then injecting the actual implementation you want at runtime. You can actually achieve this in ASP.NET Core, which supports injection in Views, but in ASP.NET MVC 5 and previous, you'd need to go a little out of your way. I'm imagining these are currently static classes, since you're referencing them merely via namespace. With that approach, you'd need to follow #Ssheverdin's advice and use the FQN of the class (i.e. with the namespace):
#if (customer == A)
{
#Resources.customerA.StaticClass.Property
}
else
{
#Resources.customerB.StaticClass.Property
}
Alternatively, you could change the static classes to be instance classes and use a factory pattern to return the right one. This is a very simplistic example, but hopefully enough to convey the idea:
public static class ResourceFactory
{
public static IResourceClass GetForCustomer(string customer)
{
switch (customer)
{
case "A":
return new Resources.customerA.ResourceClass();
default:
return new Resources.customerB.ResourceClass();
}
}
Then:
#{ var resource = ResourceFactory.GetForCustomer(customer); }
I have managed to achieve the behaviour by adding a web.config file under views folder and including the namespaces there, i have to remove the #using statement from all views obviously. You might find that intellisense doesn't work anymore for you so try closing all views and reopen them again.
With this way I can create a separate web.config file for each customer and specify the relevant namespaces accordingly. Now just have to make sure to provide the RIGHT config file for each customer when deploying the release:)

ASP.NET Web Api 2 - Subdomain Attribute Routing

I've been using AttributeRouting for quite some time in my MVC application. However, one thing it always lacked is subdomain routing in Web Api (among other features in that library that work with MVC but not Web Api).
Now I just read about the new improvements in Web Api regarding Attribute Routing and that it's now included with Web Api out of the box.
However, I see no mention of subdomain routing. Is it supported in Web Api 2?
If not, how can I get subdomain routing in my Web Api so that I can hit the ApiController using http://api.mydomain.com/cars/1?
Routing is normally used for the portion of the URL after the domain/port. As long as you have your host configured to let Web API handle requests for a domain, you should be able to route URLs within that domain.
If you do want routing to be domain-specific (such as only have requests to the api.mydomain.com domain handled by a certain route), you can use a custom route constraint. To do that with attribute routing, I think you'd need to have:
First, The custom route constraint class itself. See http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-a-custom-route-constraint-cs for an MVC domain example; the Web API interface is slightly different (http://msdn.microsoft.com/en-us/library/system.web.http.routing.ihttprouteconstraint(v=vs.108).aspx).
Second, A custom route builder. Derive from HttpRouteBuilder and override the BuildHttpRoute method to add your constraint. Something like this:
public class DomainHttpRouteBuilder : HttpRouteBuilder
{
private readonly string _domain;
public DomainHttpRouteBuilder(string domain) { _domain = domain; }
public override IHttpRoute BuildHttpRoute(string routeTemplate, IEnumerable<HttpMethod> httpMethods, string controllerName, string actionName)
{
IHttpRoute route = base.BuildHttpRoute(routeTemplate, httpMethods, controllerName, actionName);
route.Constraints.Add("Domain", new DomainConstraint(_domain));
return route;
}
}
Third, When mapping attribute routes, use your custom route builder (call the overload that takes a route builder):
config.MapHttpAttributeRoutes(new DomainHttpRouteBuilder("api.mydomain.com"));

How to do rule-based authorization with Spring Security in Grails?

Spring Security is great for doing role-based authorization, but it seems to fall short when it comes to rule-based authorization. Sure, there are ways to do it via SpEL, but going that route seems to lock your authorization logic inside the annotations when it would be much better to pull that logic out into a service so that multiple places can use the same logic.
There seem to be some ways to go about adding in your own SpEL expressions, but noting is particularly clear, and even those that make sense to me seem to fall short. I would think, given how flexible Groovy is, that there must be some way to not have to hard-code the dependencies together, but to have the security rules (or SpEL extensions) picked up at run-time.
While not ideal, even something as seemingly simple as defining all of the desired new rules and injecting the as mixins (ie. SecurityExpressionRoot.mixin MyRule1) would be a good start, but that doesn't seem to work.
Does anyone know of an example that does this? If not, how might I go about doing this myself?
One (simplified) example : A user can only take a particular action (ie. execute a service method) with an object if 3 of 4 fields have values over a particular threshold, but only if the object is less than 3 days old:
class MyRule {
boolean canTakeAction(Person person, MyThing myThing) {
int numFieldsWithValues = 0
if (myThing.field1 != null) { numFieldsWithValues++ }
if (myThing.field2 != null) { numFieldsWithValues++ }
if (myThing.field3 != null) { numFieldsWithValues++ }
if (myThing.field4 != null) { numFieldsWithValues++ }
return (numFieldsWithValues > 3) && (ageInDays(myThing) < 3)
}
int ageInDays(MyThing myThing) {
...
}
}
And that is one of the simpler rules.
Role based authorization is the easiest but less flexible way. The contrast to this is the Spring security ACL system. ACLs are let you define exaclty who is allowed to do what on which object at runtime. On the other side this requires a much more complicated setup. There is also a grails plugin for this.
The way of using annotions with SpEL expressions is somewhere between these both alternatives. They are more flexible than simple roles and easier than ACLs. If you are looking for an introduction to method security in Grails maybe this blog post I wrote some time ago can help you.
You can manage your rule in Requestmap, which provides dynamic configuration capability.
For instance, define security type as requestmap in config.groovy first:
grails.plugins.springsecurity.securityConfigType = "Requestmap"
Then you may have Requestmap domain class similar to User and Role, like this:
package com.app.auth
class Requestmap {
String url
String configAttribute
static mapping = {
cache true
}
static constraints = {
url blank: false
configAttribute blank: false
}
}
Now since User, Role, and Reqestmap are all persisted in database, you can easily change your rules by CRUD actions in some controller without need to redeploy or restart your service. Like this:
class RequestmapController {
def springSecurityService
...
def save = {
def requestmapInstance = new Requestmap(params)
if (!requestmapInstance.save(flush: true)) {
render view: 'create', model: [requestmapInstance: requestmapInstance]
return
}
springSecurityService.clearCachedRequestmaps() //This is important: to refresh the requestmap. Without it the rules remain unchanged.
flash.message = "${message(code: 'default.created.message', args: [message(code: 'requestmap.label', default: 'Requestmap'), requestmapInstance.id])}"
redirect action: show, id: requestmapInstance.id
}
}
In the view layer, you can manage your menus, buttons, and other elements need authorization by using spring security tag like:
<sec:access url="foo/bar">
<li><g:link class="list" controller="foo" action="bar">Bar action</g:link></li>
</sec:access>
Therefore, the views are also comply with the authorization rule.
Furthermore, there is a Hierarchical Roles feature which can be leveraged to reduce clutter in your request mappings.
From the example you posted, GContracts might be what you're looking for. You'd just have to figure out how to access the Principal when running a GContract closure, but that might be just as simple as passing it as a parameter to the contracted method.

Accessing Orchard CMS settings programatically inside a Module

I am writing an Orchard CMS module within a multi-tenant application.
I would like to be able to access the settings declared when the tenant was set up, namely the DB table prefix which i'd like to use as a unique identifier for the current tenant in other areas of my system.
Is there an API/Helper I can query for these settings?
Cheers.
Get the site item from the work context. It has all the settings as parts. For the table prefix specifically it's a little different: you need to inject ShellSettings. But I would question the need to do that first...
I have found this, if it helps:
private readonly ISiteService _siteService;
public MyController(ISiteService siteService)
{
_siteService = siteService;
}
public void MethodExample(){
var myVar = _siteService.GetSiteSettings().BaseUrl;
}

How can I have multiple sets of views per controller in Grails?

I'm rewriting the views for my site but I'd still like to have the originals running because the rewrite is missing features. Is there a way for me to have both and depending upon the URL pick one or the other? They'll be sharing the same domain and controller classes.
For example, http://localhost/app/* goes to the original views and http://localhost/app/test/* goes to the new views.
Thanks!
The context path when using the render function uses the name of the controller by default.
What you could do is add a parameter in your url mapping, is this satisfying ? :
class UrlMappings {
static mappings = {
"/test/$controller/$action?" {
indent = "newviewfolder/"
}
}
}
And, in a controller method
class RandomController {
render(${params.indent}"viewname", model [:], params)
}

Resources