Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement access control in Undertow #137

Open
bdw429s opened this issue Aug 4, 2018 · 6 comments
Open

Implement access control in Undertow #137

bdw429s opened this issue Aug 4, 2018 · 6 comments

Comments

@bdw429s
Copy link
Member

bdw429s commented Aug 4, 2018

There are a lot of use cases for wanting to deny access to certain URL patterns and Undertow seems to have some decent support for this. Let's think of the best way to declare access control for certain paths that makes it easy to use but it still configurable. For instance, it may be easiest to simply have a list of paths that we want to deny, but it would be better if we could allow exceptions so, for instance, the CF admin would be accessible from localhost.

Here's some example use cases:

  • Block access to CF admins
  • Block access to special files such as box.json, server.json, or .cfconfig.json
  • Block access to all files starting with a period
  • Custom folders such as /tests/ or /workbench

Undertow seems to have some capability to block based on user agent, but that seems worthless since anyone can spoof that. There is also the ability to block based on IP which which seems most useful.

Here's the docs I was able to dig up:
http://undertow.io/undertow-docs/undertow-docs-2.0.0/index.html#access-control-handler
https://repository.jboss.org/nexus/content/unzip/unzip/io/undertow/undertow-core/1.0.14.Final/undertow-core-1.0.14.Final-javadoc.jar-unzip/io/undertow/server/handlers/AccessControlListHandler.html

http://undertow.io/undertow-docs/undertow-docs-2.0.0/index.html#ip-access-control-handler
https://repository.jboss.org/nexus/content/unzip/unzip/io/undertow/undertow-core/1.0.14.Final/undertow-core-1.0.14.Final-javadoc.jar-unzip/io/undertow/server/handlers/IPAddressAccessControlHandler.html

@bdw429s
Copy link
Member Author

bdw429s commented Aug 4, 2018

@denuno
Copy link
Member

denuno commented Aug 12, 2018

We should probably set this up to jive with the basic auth stuff. I actually added some Undertow ACL code back then and played with it a little:

https://github.com/cfmlprojects/runwar/blob/master/src/main/java/runwar/security/SecurityManager.java#L77

IIRC we just need to figure out how to define the ACL...

This is another thing that looks a lot better in JSON than on the command line, and roles will be rough regardless because duplication/misspelling/etc..

See this issue for previous discussion: #64

I'm thinking maybe something like this to cover both:

{
    "web":{
        "security":{
            "type": "basicAuth",
            "users":{
                "brad":"wood",
                "guest":"password",
            },
            "roles" : { 
                 "admin" : [ "brad" ],
                  "public": [ "guest", "brad" ] 
            },
            "paths" : {
                "/foo" : {
                   "users":["guest","brad"],
                   "roles":["public"]
                },
                "/admin/bar" : {
                   "roles":["admin"]
                }
            },
            "enable":"true"
        }
    }
}

Perhaps the security element should have a sub-element named basicAuth with the info in it, versus the type attribute, but generally a structure along those lines.

@denuno
Copy link
Member

denuno commented Aug 12, 2018

Paths with no users/roles are forbidden? I dunno, seems like this and the existing auth stuff should go together though.

@bdw429s
Copy link
Member Author

bdw429s commented Aug 14, 2018

I think we should simplify it a bit of not necessarily offer everything Undertow does. For what it's worth, I'm not sure if many people ever even use the basic auth feature. To get some perspective, the two actual use case scenarios I really have at this point are:

  • Block ALL traffic to a path or path pattern
  • Block IP ranges to a path or path pattern

I really don't want to go nearly as complicated with what's above when I could solve 99% of what my users are currently asking for with something really as simple as a selective whitelist:

"firewall" : {
  "/box.json" : "",
  "/server.json" : "",
  "/CFIDE/*" : "127.0.0.*,10.10.0.*"
}

So the ideal solution maybe is somewhere in between the two. I really don't want to get into any role nonsense-- that can be left up to the application. I'd be fine if we could have a simple map of path patterns that pointed to a whitelist of IP ranges (empty means no one can access) or a map of username/passwords. Maybe then we could tie in basic auth like that so securing your entire site would just be a pattern of /* then the users you wanted.

"firewall" : {
  "/box.json" : "",
  "/*" : {
       "brad" : "brads pass",
       "denny" : "dennys pass"
    }
}

I mainly just want to make sure we worry about keeping the simple use cases simple more than we worry about supporting some of the crazier edge cases. Another question to answer is whether the order of the rules matters. If so, I'd make it an array in the config.

@bdw429s
Copy link
Member Author

bdw429s commented Aug 16, 2018

I got another bit of info from Stuart on the Undertow-dev list today which is interesting. Undertow has a string syntax that allows you to specify (in some sort of config file) a parsable DSL that declares your predicates such as path matching patterns and what to do with them.

path-suffix(/box.json) -> response-code(404)

That string above would return a 404 for any box.json files. Here's some docs:

https://github.com/undertow-io/undertow-docs/blob/master/src/main/asciidoc/predicates-attributes-handlers.asciidoc

Undertow's so-called "predicate language" seems really powerful, although perhaps not 100% obvious for a first time reader. I can't help but think it would be super cool to allow users to pass predicates directly to Undertow. You could configure just about anything with the right combination it looks like.

So I think the million dollar question now is how can we keep some of those simple use cases above still stay simple and not require CommandBox/Runwar users to bother learning Undertow's predicate language but still leave it open for advanced users to tap into it and basically do unlimited stuff. According to Undertow, predicates/handlers are executed in the order defined, so either way I'd need to collect them as an array and we'd want to load them before the built in CFML handlers in Runwar so they can do things like security, rewrites, etc.

If we just straight up let people use Undertow's predicate language, the config could be as simple as this:

"rules" : [
  "path-suffix(/box.json) -> response-code(404)",
  "path-prefix(.) -> response-code(404)",
  "path-prefix(/admin/) -> ip-access-control(192.168.0.* allow)",
  "path-template(/sitemap.xml) -> rewrite(/sitemap.cfm)"
]

I'm really liking all the powerful things we could do here without needing to explicitly add support for all of them, just passing through the predicate and handler to Undertow. A note on this-- we need to figure out how to enable logging for this stuff or debugging it might be near impossible.

Another idea would be a mashup of the two, where we choose a default predicate and handler that we think would apply to 90% of all the use cases to reduce boilerplate and typos and then still allow the user to pass a full predicate/handler if they wish as an "advanced" feature.

// Default predicate as regex and default handler as response-code
"rules" : [
  { match=".*/box.json", response="404" },
  { match="\..*", response="404" },
  { predicate="path-prefix(/admin/) -> ip-access-control(192.168.0.* allow)" )
]

Yeah, I dunno. Now that I type up and read that last example, I'm not sure if it's really any more readable or simple than the previous example that just relies 100% on Undertow's predicate language.

The only thing we haven't accounted for here is basic auth (I'm not sure exactly how it ties in with the predicates or whether it's part of Undertow's predicate language). I'm not quite as worried about basic auth however since it's not used a lot and we already have an existing implementation that allows you to apply it to the entire site. The only thing you can't do right now which I think would be handy is to apply basic auth to a subdirectory, or a predicate of some sort. I do think that could be handy.

Thoughts?

@bdw429s
Copy link
Member Author

bdw429s commented Aug 31, 2018

@denuno What do you think about that Undertow predicate language and what would it take for you to tap into it? I think I'd like to experiment with something in CommandBox where I let the user give me an ordered list of Undertow predicates and handlers. The power of undertow's predicate DSL has sort of grown on me.

"rules" : [
  "path-suffix(/box.json) -> response-code(404)",
  "path-prefix(.) -> response-code(404)",
  "path-prefix(/admin/) -> ip-access-control(192.168.0.* allow)",
  "path-template(/sitemap.xml) -> rewrite(/sitemap.cfm)"
]

I think the only real question left is, "How do I pass this from CommandBox to Undertow?"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants