Closed danbim closed 11 years ago
Shiro needs to added as a filter to the servlet in the service-publisher
.
Programmatically adding filters is possible from servlet API v3 on (which we are using).
I didn't find a place where the ServicePublisher
exposes a ServletContext
...
I've added a method to expose the ServletContextHandler so you can add filters (see commit https://github.com/itm/service-publisher/commit/c9b1a166b587ddbbbeb4ecf5832b48749d698323). Please be aware that I'm not aware about the lifecycle model here (i.e. if you're allowed to add filters after the servlet has been started). If this does not work we can change the model so that you have to pass in filters when creating the service.
I've implemented a custom Shiro realm that can be configured in a web applications web.xml
file as in the following example:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<!-- ... -->
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<!-- ... -->
</web-app>
Then, you also need a WEB-INF/shiro.ini
file that contains some definitions like in this example:
[main]
realm=de.uniluebeck.itm.tr.snaa.shiro.ShiroSNAARealm
realm.jpaProperties=/path/to/tr_snaa.jpa.properties
myFilter=de.uniluebeck.itm.tr.snaa.shiro.HttpMethodRolesAuthorizationFilter
[urls]
/index.jsp = anon
/authenticated.jsp = authcBasic
/authorized_admin.jsp = authcBasic, roles[ADMINISTRATOR]
/authorized_experimenter.jsp = authcBasic, roles[EXPERIMENTER]
/authorized_sp.jsp = authcBasic, roles[SERVICE_PROVIDER]
/logout = logout
/rest = authcBasic, myFilter[PUT=SERVICE_PROVIDER&EXPERIMENTER,POST=EXPERIMENTER,DELETE=ADMINISTRATOR]
In the main section the abovementioned custom Shiro realm is initialized that uses the database backend of ShiroSNAA.
The filter myFilter
is a custom filter that allows to check authorization for users based on their roles and on the request method (GET, PUT, POST, DELETE ...) that was used. This feature was not implemented in Shiro itself, therefore a custom module was necessary.
The property realm.jpaProperties
points to another properties file that contains the configuration on how to connect to the database (should be exactly the same file that is used to run ShiroSNAA itself). An example is given here:
hibernate.connection.url = jdbc:mysql://localhost:3306/tr_snaa
hibernate.connection.driver_class = com.mysql.jdbc.Driver
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.hbm2ddl.auto = update
hibernate.connection.username = TR
hibernate.connection.password = TR
# configure connection pooling for production servers
hibernate.connection.provider_class=org.hibernate.connection.C3P0ConnectionProvider
hibernate.c3p0.acquire_increment=1
hibernate.c3p0.idle_test_period=60
hibernate.c3p0.min_size=1
hibernate.c3p0.max_size=10
hibernate.c3p0.max_statements=50
hibernate.c3p0.timeout=10
hibernate.c3p0.acquireRetryAttempts=1
hibernate.c3p0.acquireRetryDelay=250
In order to be able to use the aforementioned functionality in your web application you need to include the SNAA JAR file e.g., by adding it to the dependencies section of your POM (in case you're using a Maven-based web app):
<dependencies>
<!-- ... -->
<dependency>
<groupId>de.uniluebeck.itm</groupId>
<artifactId>tr.snaa</artifactId>
<version>0.9-SNAPSHOT</version>
</dependency>
<!-- ... -->
</dependencies>
as well as the ITM Maven repositories where this dependency can be found
<repository>
<id>itm-maven-repository-releases</id>
<url>http://maven.itm.uni-luebeck.de/content/repositories/releases/</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots>
</repository>
<repository>
<id>itm-maven-repository-snapshots</id>
<url>http://maven.itm.uni-luebeck.de/content/repositories/snapshots/</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
In reality an operation has to be allowed for users with different roles. So e.g., it might be necessary to allow PUT operations for SERVICE_PROVIDERs and ADMINISTRATORs but not for EXPERIMENTERs. With the current implementation this is not possible as only conjunctions of roles are possible (which is probably an extremly rare use case (at least for TR it's non-existent)). So, config should look like this:
/rest = authcBasic, myFilter[PUT=SERVICE_PROVIDER|EXPERIMENTER,POST=EXPERIMENTER,DELETE=ADMINISTRATOR]
Please note the pipe |
between SERVICE_PROVIDER
and EXPERIMENTER
for the PUT
case. This indicates that a user is authorized to execute the action if he either is a service provider or an experimenter.
See 3c45a27f743d53e40cbbdf02ebd6d1f1930ef851 for implementation.
One remaining issue is that anon users should be able to e.g., get GET access to resources even if PUT/POST/DELETE/... is forbidden to them. The solution is simply to pass a "permissive" flag to the "authcBasic" filter of Shiro. If given, this filter will let the request through even though the user is not authenticated so the next filter in the chain can decide if anon access should be allowed.
An example shiro.ini
file:
[main]
realm=de.uniluebeck.itm.tr.snaa.shiro.ShiroSNAARealm
realm.jpaProperties=/Coding/smartsantander/sms-trunk/auth-webapp/tr_snaa.jpa.properties
httpMethodRoleFilter=de.uniluebeck.itm.tr.snaa.shiro.HttpMethodRolesAuthorizationFilter
[urls]
/rest = authcBasic[permissive], httpMethodRoleFilter[PUT=SERVICE_PROVIDER|EXPERIMENTER,POST=EXPERIMENTER,DELETE=ADMINISTRATOR]
This will allow anonymous access to /rest for GET but access to PUT/POST/DELETE is only granted for authenticated users that have (one of) the corresponding role(s).
This module can e.g., be used for #292 but also in other Servlet-based applications that integrate with TR. E.g., the SmartSantander RD could use the module to check authorization of users trying to update the resource descriptions. TR plugins could also use this module if the want to publish web pages (e.g., usage statistics).
This extensive documentation on how to use a Shiro realm implementation in a Servlet container could help.