Skip to content

AuthenticationAuthorization

Martin Goellnitz edited this page Sep 1, 2016 · 6 revisions

Authentication and Authorization

Tangram provides a set of components to deal with authentication and authorization. While the authorization parts a very simple, then authentication architecture should be sufficient for nearly any use case. Of course the user's view to these features must be implemented suiting the needs of the web application.

The authentication and authorization in Tangram heavily relies on the pac4j project and consists of three main components:

The authorization which is tailored towards the internal needs of tangram, using a subset of the authentication, defining URLs which do not need any authorization by the base system, and defining users which are authorized to use the internal components of tangram like the importer and exporter and the [Tangram Generic Editor] (Editor).

The authentication component provides an abstraction layer for user authentication so that the web application has a uniform way to handle users and their logins. Also it supports login pages or login module on pages.

Still the authentication component is independent of the login backend in use relying on a list of so called login providers which handle the login depending on the backend in use.

Login Providers

A login provider is nothing else than a pac4j Client implementation configured for your application using the Dependency Injection framework in use. The only thing Tangram adds to you configuration is the URL handling for login callbacks so that you don't have to deal with that at all.

In the default configurations Tangram comes with the form based login and http basic authentication login providers set up. Their are only missing a user base which is added through a username to password mapping (see below).

Other logins can be easily added to be able to use twitter, google, Yahoo, and so on.

E.g. to use OAuth based twitter logins with the provider name twitter you will have to setup an instance of the class org.pac4j.oauth.client.TwitterClient with the name twitter and a secret and a key provided by twitter.

  <!-- Example twitter login client -->
  <bean id="yahooLogin" class="org.pac4j.oauth.client.TwitterClient">
    <property name="name" value="twitter"/>
    <property name="key" value="providedbytwitter"/>
    <property name="secret" value="providedbytwitter"/>
  </bean>

Yahoo OpenID based login are even easier to set up, since the only need a name attached. The Springframework example for this case is

  <!-- Example additional login client -->
  <bean id="yahooLogin" class="org.pac4j.openid.client.YahooOpenIdClient">
    <property name="name" value="yahoo"/>
  </bean>

Don't forget to add the OpenID dependecy for pac4j in this case:

dependencies {
  ...
  // For Yahoo OpenID example
  runtime "org.pac4j:pac4j-openid:$versions.pac4j"
  ...
}

For its internal purposes Tangram holds a list of login providers as a subset of the login providers configured. This list is used when checking authorizations for the use of the internal facilities and redirecting to a login when the user is not authorized.

Your application may decide to use this list or directly use any providers configured.

Authentication Service

When your application decides, that the user needs to authentice himself, you simply ask the authentication service for the login target to redirect to.

TargetDescriptor target = authenticationService.getLoginTarget(loginProviders);

You will need to pass as set of login provider names to this call so that you application can decide which external services should be allowed for the user.

If this list is just the same as you use for Tangram internally, there is a short cut in the authorization service to handle this and also deal with the handling of a return url bringing the user pack to the originating page after the login.

TargetDescriptor target = authorizationService.getLoginTarget(request);

If you don't like the default login page, you can easily override it with the standard Tangram view means.

Protected Content

No automatic redirect to login pages.

Login may be a fragment.

Be aware to hide stuff yourself.

If you don't like the default login page are login fragment you can easily override it with the standard Tangram view means.

Free URLs

Some URLs must not be considered when checking for login and redirecting to a login page in any case. These URLs are called "free URLs" and at least need to contain URLs for login handling. Be aware that also external login providers need a redirecting URL internal to your application to come back after login.

spring free URL list example from an application.xml configuration file:

<util:set id="freeUrls" value-type="java.lang.String">
    <value>${tangram.servlet.path}/stats</value>
    <value>${tangram.servlet.path}/login</value>
    <value>${tangram.servlet.path}/callback</value>
    <value>${tangram.servlet.path}/login-form</value>
    <value>${tangram.servlet.path}/redirect/form</value>
    <value>${tangram.servlet.path}/redirect/basic</value>
    <value>${tangram.servlet.path}/redirect/yahoo</value>
    <value>${tangram.servlet.path}/redirect/twitter</value>
    <value>${tangram.servlet.path}/redirect/google</value>
</util:set>

guicy free URL list from an example application's tangram.properties file:

# urls free to access
freeUrls=/s/stats,/s/login,/s/callback,/s/redirect/gae,/s/redirect/form,\
         /s/redirect/yahoo,/s/redirect/twitter,/s/login-form)

dinistiq free URL list in an application.properties example file:

freeUrls=java.util.Set(/s/stats,/s/login,/s/callback,/s/redirect/form,\
                       /s/redirect/yahoo,/s/redirect/twitter,/s/login-form)

Username Password Mapping

The basic authentication and the form authentication need a username to password mapping in order to check, if a login with username and credentials was valid.

Internally this is achieved by a simple map mapping usernames to SHA256 hashes. When using the form or basic authentication this map must be present but obviously should only contain a very minimal set of logins which do not change very often (and at least one admin login).

spring username password mapping example from an application xml configuration file:

<util:map key-type="java.lang.String" value-type="java.lang.String"
          id="usernamePasswordMapping">

  <entry key="user"
         value="04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb" />
  <entry key="admin"
         value="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918" />

</util:map>

guicy username password mapping from an application.groovy configuration example:

log.info("configuring name password mapping")
Map<String,String> mapping = new HashMap<>()
mapping.put('admin',
            '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918')
mapping.put('user',
            '04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb')
module.bind(module.stringStringMap).
  annotatedWith(Names.named("usernamePasswordMapping")).
  toInstance(mapping)

dinistiq username password mapping in a usernamePasswordMapping.properties example:

admin=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
user=04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb

Authorization

Since the authorizations of a logged in user are a very application specific part, Tangram itself only deals with the needs of some internal components. Furthermore Tangram for this purpose only defined one role which is considered an "admin" role. Admins are allowed to use the Tangram Generic Editor and other tools from the Tangram based application.

Internally Tangram holds a list of admin users. Each user in this list is defined by the login provider to use and the username within that provider. (s.a.)

spring admin list example from an application xml configuration file:

<util:set id="adminUsers" value-type="java.lang.String">
  <value>form:admin</value>
</util:set>

guicy admin list from an example application's tangram.properties file:

# admin users to be allowed to edit content
adminUsers=form:admin,basic:admin

dinistiq admin list in an application.properties example file:

adminUsers=java.util.Set(form:admin,basic:admin)

Password checking Interceptor

All the remaining bits and pieces of this chapter heavily rely on an interception instance which checks each and every http call if it is authenticated.

Without this instance which provides essential handling of logged in users, non of the following components will work.

Due to the fact that we have different types of web integration - Springframework and all the others using the Java Servlet API directly - the details of the configuration of this interceptor vary, since there are two implementations of it: One as a Servlet API Filter, one as a Springframework interceptor.

The http request handling in the interceptor is delegated to the authorization service.

Closed Applications

With the default settings the application - not the Tangram editor - is open to the public. The authentication framework supports the application in implementing its own security model.

If the model is that simple, that like with the editor all pages are only visible for a set of users, there is an easy solution which is also inteded for the development phase of an application where it should be avaible on the internet but only to a closed set of reviewing people / first friendly users.

In addition to the list of admin users there is a list of allowed users which is empty by default making the application globally available.

When you enter a list of users with annotated login providers where like with the admin users list, you get a globally protected application which requires login for every access.

spring allowed user list example from an application xml configuration file:

<util:set id="allowedUsers" value-type="java.lang.String">
  <value>form:admin</value>
  <value>form:mike</value>
</util:set>

guicy allowed user list from an example application's tangram.properties file:

# allowed users to log into the application
allowedUsers=form:admin,form:mike

dinistiq allowed user list in an application.properties example file:

allowerUsers=java.util.Set(form:admin,form:mike)

Dynamic Extensions

Since users need to be added and removed more often than you might want to deploy your application, users and admin role can be defined in the repository.

You have to create and maintain a code resource with the annotation users.properties and the mime type text/plain. Each line of this resource maps a username to a SHA256 hash value like in the dinistiq example for the static case above.

jeff=2e0b8d61fa2a6959d254b6ff5d0fb512249329097336a35568089933b49abdde

Also some of the users - be they defined within the application configuration or the repository - can be added to the list of users in the "admin" role. You simply have to add a mapping line "admins" with a comma separated list of additional admin users not presented statically in the application configuration.

jeff=2e0b8d61fa2a6959d254b6ff5d0fb512249329097336a35568089933b49abdde
adminUsers=form:user,form:jeff

If your are using a globally protected application - the static list "allowedUsers" is not empty - you also can add allowed users dynamically:

jeff=2e0b8d61fa2a6959d254b6ff5d0fb512249329097336a35568089933b49abdde
adminUsers=form:user
allowedUsers=form:user,form:jeff
Clone this wiki locally