Ticket #293 (closed Enhancement: fixed)
Backend security
Reported by: | jri | Owned by: | jri |
---|---|---|---|
Priority: | Critical | Milestone: | Release 4.1 |
Component: | DeepaMehta Standard Distribution | Version: | 4.0.11 |
Keywords: | Cc: | dgf, Malte | |
Complexity: | 13 | Area: | |
Module: |
Description (last modified by jri) (diff)
Each HTTP request must pass a filter chain for authorization. The authorization check must involve the instance's ACLs entries (#262) and the user's authentication status. The user session must be represented by a server-side HTTP session whose ID is stored in a browser cookie. If request authorization fails 401 or 403 must be returned.
Thanks, dgf, for pushing this topic now!
and for the Spring Security hint.
Change History
comment:3 Changed 12 years ago by jri
The missing Servlet Context Listeners seems not to be a problem at all. Despite some disadvantages the Shiro SecurityManager? object can be constructed programatically. See http://shiro.apache.org/configuration.html
comment:4 Changed 12 years ago by dgf
Another possibility can be the JSR 250 support of jersey
an short introduction: Jersey JAX-RS, Tomcat, Basic Auth and Security Annotations
a programmatically filter configuration is also supported
class WebPublishingService .... String[] filters = new String[]{RolesAllowedResourceFilterFactory.class.getName()}; rootApplication.getProperties().put(ResourceFilters.class.getName(), filters); jerseyServlet = new ServletContainer(rootApplication);
comment:5 Changed 12 years ago by jri
Thanks, dgf, for that hint!
The Jersey filters open a set of new possibilities.
Perhaps we can start even without using a security framework.
My next goal is securing the application as whole:
1) Starting the Webclient must require to login. That is, the very first request must result in 401 if not logged in.
This requires securing the static resources (scripts). As these are not delivered by Jersey (but Jetty directly) I will try to setup a Filter (Servlet API, not Jersey API) via Felix's ExtHttpService?.
2) For securing the REST resources I will try Jersey Container Filters. All REST resources must accessible only for logged in users.
Finer granularity (ACL-based at instance-level) could be realized later on by the Jersey Resource Filters you mentioned.
Thanks, dgf, for the phone discussion!
comment:6 Changed 12 years ago by Jörg Richter
Core: try out Jersey Container Filters (#293).
Just an experiment. Nothing useful for the moment.
See ticket 293.
comment:7 Changed 12 years ago by Jörg Richter
Core: try out Servlet Filters (#293).
Just an experiment. Nothing useful for the moment.
See ticket 293.
comment:8 Changed 12 years ago by Jörg Richter
Core: new setting dm4.installation.type (#293).
There are 4 DeepaMehta installation types (left column):
Net Interface Read Write ------------------------------------------------------------------------ SINGLE-USER localhost yes yes (default) PRIVATE all if logged in if logged in PUBLIC all yes if logged in SANDBOX all yes yes
See ticket 293.
comment:9 Changed 12 years ago by Jörg Richter
Extend Access Control service by login() (#293).
See ticket 293.
comment:10 Changed 12 years ago by Jörg Richter
Access Control: fix cyclic dependency (#293).
The request filter is setup by the Access Control plugin (instead by DM4 Core).
Changed in Access Control service:
- login() renamed to checkCredentials()
- getUsername() has no parameter anymore ("clientState" is dropped)
- getTopicPermissions() has no "clientState" parameter anymore
Furthermore in DM4 Core: a plugin can register a (Servlet API) filter by calling
- registerFilter(Filter filter) declared in plugin base class
See ticket 293.
comment:11 Changed 12 years ago by Jörg Richter
Access Control: create HTTP sessions (#293).
For a logged in user a HTTP session is created.
The dm4_username cookie is not used anymore.
Furthermore in Webclient: the API method require_login() is removed.
See ticket 293.
comment:12 Changed 12 years ago by Jörg Richter
Access Control: logout (#293).
Once logged out the HTTP session is invalidated.
Changes in Access Control service:
- logout() is added
- lookupUserAccount() is dropped
See ticket 293.
comment:13 Changed 12 years ago by Jörg Richter
Access Control: drop "installation type" (#293).
Instead the "dm4.installation.type" config property there are 2 separate boolean properties in global pom.xml:
- dm4.security.read_requires_login # default is "false"
- dm4.security.write_requires_login # default is "true"
See ticket 293.
comment:14 Changed 12 years ago by Jörg Richter
Access Control: logout shuts down client (#293).
When logging out from a "private" DM installation the webclient shuts down, that is the browser window is emptied. This reflects the meaning of a "private" installation: the webclient is only accessible when logged in.
A DM installation is made "private" by setting the config property dm4.security.read_requires_login to true (in global pom.xml):
<dm4.security.read_requires_login>true</dm4.security.read_requires_login>
Note this drawback: the next request logs in the user automatically. This is a known problem with HTTP Basic authentication.
See ticket 293.
comment:15 Changed 12 years ago by Jörg Richter
Access Control: global subnet filter (#293).
The subnet filter of the Files plugin is moved to the Access Control plugin.
The subnet check is applied to *every* request (not just file requests).
There is a new config property in global pom.xml:
<dm4.security.subnet_filter>127.0.0.1/32</dm4.security.subnet_filter>
The former dm4.filerepo.netfilter property is dropped.
See ticket 293.
comment:16 Changed 12 years ago by Jörg Richter
Core: try out Jersey Container Filters (#293).
Just an experiment. Nothing useful for the moment.
See ticket 293.
comment:17 Changed 12 years ago by Jörg Richter
Core: try out Servlet Filters (#293).
Just an experiment. Nothing useful for the moment.
See ticket 293.
comment:18 Changed 12 years ago by Jörg Richter
Core: new setting dm4.installation.type (#293).
There are 4 DeepaMehta installation types (left column):
Net Interface Read Write ------------------------------------------------------------------------ SINGLE-USER localhost yes yes (default) PRIVATE all if logged in if logged in PUBLIC all yes if logged in SANDBOX all yes yes
See ticket 293.
comment:19 Changed 12 years ago by Jörg Richter
Extend Access Control service by login() (#293).
See ticket 293.
comment:20 Changed 12 years ago by Jörg Richter
Access Control: fix cyclic dependency (#293).
The request filter is setup by the Access Control plugin (instead by DM4 Core).
Changed in Access Control service:
- login() renamed to checkCredentials()
- getUsername() has no parameter anymore ("clientState" is dropped)
- getTopicPermissions() has no "clientState" parameter anymore
Furthermore in DM4 Core: a plugin can register a (Servlet API) filter by calling
- registerFilter(Filter filter) declared in plugin base class
See ticket 293.
comment:21 Changed 12 years ago by Jörg Richter
Access Control: create HTTP sessions (#293).
For a logged in user a HTTP session is created.
The dm4_username cookie is not used anymore.
Furthermore in Webclient: the API method require_login() is removed.
See ticket 293.
comment:22 Changed 12 years ago by Jörg Richter
Access Control: logout (#293).
Once logged out the HTTP session is invalidated.
Changes in Access Control service:
- logout() is added
- lookupUserAccount() is dropped
See ticket 293.
comment:23 Changed 12 years ago by Jörg Richter
Access Control: drop "installation type" (#293).
Instead the "dm4.installation.type" config property there are 2 separate boolean properties in global pom.xml:
- dm4.security.read_requires_login # default is "false"
- dm4.security.write_requires_login # default is "true"
See ticket 293.
comment:24 Changed 12 years ago by Jörg Richter
Access Control: logout shuts down client (#293).
When logging out from a "private" DM installation the webclient shuts down, that is the browser window is emptied. This reflects the meaning of a "private" installation: the webclient is only accessible when logged in.
A DM installation is made "private" by setting the config property dm4.security.read_requires_login to true (in global pom.xml):
<dm4.security.read_requires_login>true</dm4.security.read_requires_login>
Note this drawback: the next request logs in the user automatically. This is a known problem with HTTP Basic authentication.
See ticket 293.
comment:25 Changed 12 years ago by Jörg Richter
Access Control: global subnet filter (#293).
The subnet filter of the Files plugin is moved to the Access Control plugin.
The subnet check is applied to *every* request (not just file requests).
There is a new config property in global pom.xml:
<dm4.security.subnet_filter>127.0.0.1/32</dm4.security.subnet_filter>
The former dm4.filerepo.netfilter property is dropped.
See ticket 293.
comment:26 Changed 12 years ago by jri
- Status changed from new to closed
- Resolution set to fixed
Summary:
The backend (its REST API) is secured at a coarse level: each request must pass a filter. The filter is controlled by 3 config properties:
dm4.security.read_requires_login # default: false dm4.security.write_requires_login # default: true dm4.security.subnet_filter # default: 127.0.0.1/32
This is sufficient e.g. to deploy a shared private DM installation -> set both flags to ”true" and the netfilter to "0.0.0.0/0".
No (per-instance) ACLs are involved at this level.
For the moment this is considered sufficient and the ticket is now closed.
comment:27 Changed 12 years ago by Jörg Richter
Access Control: login is a POST request (#293).
Login via REST API now uses Basic Authentication.
To login:
POST /accesscontrol/login
Put username and passwort in the "Authorization" header, according to Basic Authentication:
The string "Basic " appended by the Base64 encoded form of "{username}:{password}".
Note: no RequestFilter? rule exception is required. The POST request is autorized on-the-fly via Basic Authentication.
(Basic Authentication allows to send the "Authorization" header along with the initial request, not forcing a 401).
Further changes in Webclient:
The RESTClient's public request() method takes a "headers" object (replacing the "content_type" parameter).
A plugin can pass arbitrary request headers.
this.request = function(method, uri, data, headers)
See ticket 293.
comment:28 Changed 12 years ago by Jörg Richter
Access Control: login is a POST request (#293).
Login via REST API now uses Basic Authentication.
To login:
POST /accesscontrol/login
Put username and passwort in the "Authorization" header, according to Basic Authentication:
The string "Basic " appended by the Base64 encoded form of "{username}:{password}".
Note: no RequestFilter? rule exception is required. The POST request is autorized on-the-fly via Basic Authentication.
(Basic Authentication allows to send the "Authorization" header along with the initial request, not forcing a 401).
Further changes in Webclient:
The RESTClient's public request() method takes a "headers" object (replacing the "content_type" parameter).
A plugin can pass arbitrary request headers.
this.request = function(method, uri, data, headers)
See ticket 293.
comment:29 Changed 12 years ago by Jörg Richter
Core: try out Jersey Container Filters (#293).
Just an experiment. Nothing useful for the moment.
See ticket 293.
comment:30 Changed 12 years ago by Jörg Richter
Core: try out Servlet Filters (#293).
Just an experiment. Nothing useful for the moment.
See ticket 293.
comment:31 Changed 12 years ago by Jörg Richter
Core: new setting dm4.installation.type (#293).
There are 4 DeepaMehta installation types (left column):
Net Interface Read Write ------------------------------------------------------------------------ SINGLE-USER localhost yes yes (default) PRIVATE all if logged in if logged in PUBLIC all yes if logged in SANDBOX all yes yes
See ticket 293.
comment:32 Changed 12 years ago by Jörg Richter
Extend Access Control service by login() (#293).
See ticket 293.
comment:33 Changed 12 years ago by Jörg Richter
Access Control: fix cyclic dependency (#293).
The request filter is setup by the Access Control plugin (instead by DM4 Core).
Changed in Access Control service:
- login() renamed to checkCredentials()
- getUsername() has no parameter anymore ("clientState" is dropped)
- getTopicPermissions() has no "clientState" parameter anymore
Furthermore in DM4 Core: a plugin can register a (Servlet API) filter by calling
- registerFilter(Filter filter) declared in plugin base class
See ticket 293.
comment:34 Changed 12 years ago by Jörg Richter
Access Control: create HTTP sessions (#293).
For a logged in user a HTTP session is created.
The dm4_username cookie is not used anymore.
Furthermore in Webclient: the API method require_login() is removed.
See ticket 293.
comment:35 Changed 12 years ago by Jörg Richter
Access Control: logout (#293).
Once logged out the HTTP session is invalidated.
Changes in Access Control service:
- logout() is added
- lookupUserAccount() is dropped
See ticket 293.
comment:36 Changed 12 years ago by Jörg Richter
Access Control: drop "installation type" (#293).
Instead the "dm4.installation.type" config property there are 2 separate boolean properties in global pom.xml:
- dm4.security.read_requires_login # default is "false"
- dm4.security.write_requires_login # default is "true"
See ticket 293.
comment:37 Changed 12 years ago by Jörg Richter
Access Control: logout shuts down client (#293).
When logging out from a "private" DM installation the webclient shuts down, that is the browser window is emptied. This reflects the meaning of a "private" installation: the webclient is only accessible when logged in.
A DM installation is made "private" by setting the config property dm4.security.read_requires_login to true (in global pom.xml):
<dm4.security.read_requires_login>true</dm4.security.read_requires_login>
Note this drawback: the next request logs in the user automatically. This is a known problem with HTTP Basic authentication.
See ticket 293.
comment:38 Changed 12 years ago by Jörg Richter
Access Control: global subnet filter (#293).
The subnet filter of the Files plugin is moved to the Access Control plugin.
The subnet check is applied to *every* request (not just file requests).
There is a new config property in global pom.xml:
<dm4.security.subnet_filter>127.0.0.1/32</dm4.security.subnet_filter>
The former dm4.filerepo.netfilter property is dropped.
See ticket 293.
comment:39 Changed 12 years ago by Jörg Richter
Access Control: login is a POST request (#293).
Login via REST API now uses Basic Authentication.
To login:
POST /accesscontrol/login
Put username and passwort in the "Authorization" header, according to Basic Authentication:
The string "Basic " appended by the Base64 encoded form of "{username}:{password}".
Note: no RequestFilter? rule exception is required. The POST request is autorized on-the-fly via Basic Authentication.
(Basic Authentication allows to send the "Authorization" header along with the initial request, not forcing a 401).
Further changes in Webclient:
The RESTClient's public request() method takes a "headers" object (replacing the "content_type" parameter).
A plugin can pass arbitrary request headers.
this.request = function(method, uri, data, headers)
See ticket 293.
There is a variety of security frameworks for that purpose. Popular ones include
Here is my first impression:
Spring Security is complicated. Perhaps too complicated. At least not very accessible for a first-time (non-Spring) user.
Apache Shiro on the other hand feels very friendly. Easy to understand concepts and clear wording. Very good documentation, also for beginners. For the time being Apache Shiro is clearly my favorite.
But what could render headaches is, again, the OSGi environment. In particular the limits of its HTTP service. The OSGi HTTP service specification neither supports (Servlet API) Filters nor Servlet Context Listeners. While Felix HTTP provides a non-standard extension for Filters (same for Equinox) there is no support for Listeners.
Since version 1.2 Apache Shiro relies on Servlet Context Listeners as the central Shiro SecurityManager? object is created in a Listener. The previous version, Shiro 1.1, in contrast creates the SecurityManager? in a Filter which might work well with Felix.
Things we could consider: