Clients

Client configurations, aliases and URLs

When you configure a client by creating a <client:config> section in a config.xml file you're actually creating a unique URL that the user can access that particular client from.

For example if you create a client config with the id of 'main'

Basic client configuration
<client:config id="main">
  <title>My Super Client</title>
  <!-- other config content goes here -->
</client:config>

The the users will be able to access the client using /weave/main.html.
Similarly if you create a client config with the id 'test' or 'external' then direct URL would be /weave/test.html and /weave/external.html respectively.

The extensions .html and .htm can both be used to access the clients.

index.html and the default client

index.html is a special page that's handled by Weave differently. For a start this is the page that will be displayed if they don't specify a client directly, that is, /weave/ will in fact display the equivalent content of /weave/index.html.

Furthermore index.html does some additional processing depending upon who the user is and how many clients configurations you've created.

Ignoring security for a moment, assuming everyone has access to everything, if you only have a single client configured then index.html will just forward the user to that one client, e.g. /weave/ will forward to /weave/index.html, then /weave/index.html will forward to /weave/main.html (assuming the only client you have configured has the id of 'main').

If however you have multiple clients configured then if the user accesses index.html, either directly or indirectly, then the user is presented with a page containing a list of the clients that are available, and they must choose a specific client that they want to access before the client proper will be loaded.

You can disable the display of a specific client in this list by setting publish to false in the client config.

Hiding a client configuration
<client:config id="test">
  <publish>false</publish>
  <title>My Test Client</title>
  <!-- other config content goes here -->
</client:config>

Note that if this results in there only being a single published client available then the user will again be automatically redirected to that client.

You can also completely disable a client configuration by setting enable to false.

Disabling a client configuration
<client:config id="test">
  <enable>false</enable>
  <title>My Test Client</title>
  <!-- other config content goes here -->
</client:config>

This is would be the equivalent of completely removing the client configuration from the config.xml file, and is useful for quickly removing access to a client without having to remove it from the .xml file.

Access control and index.html

Bringing security back into the picture alters the landscape slightly. Specifically in the situation where a client config has an ACL attached to it and the user does not pass the ACL check, then the user will not have access to that client config.

This could mean that the user is reduced to a single client config (assuming there is one other client config wither with an ACL that the user passes or it doesn't have an ACL at all) in which case they'll be directed to that config in the same way as they would if there were only one client config.
Or, if they have more than one client config accessible, after the ACL checks, then they'll again be presented with the page listing all available client, but the page will only display those clients that the user has access to (and that are published and enabled).
Finally, if they have no client configs accessible then they'll be directed to a login page.

Client config only available to users that pass the 'admin' acl
<client:config id="test">
  <acl>admin</acl>
  <title>My Test Client</title>
  <!-- other config content goes here -->
</client:config>

Just because a client config has an ACL attached to it does not mean that a user will not be able to access that client config, either if they're logged on or not, since the ACL may specify that 'anonymous' users are acceptable.

In addition to displaying the list of available client the list page also includes a button that allows the user to login (this button will allow the user to logout if they're already logged in). This button will direct the user to the login.html page, this is the same login page that the user would be directed to if they did not have access to any client configurations because of ACL's.

This page provides the user with an opportunity to login top gain access to the system if all clients are locked down and the user has not already been authenticated (for example by using NTLM authentication which generally occurs before the index.html page is displayed).

Advanced access control with security.xml

Restricting anonymous access

There are two ways to restrict access to Weave so that a user has to be authenticated before they can access the system (well three if you count automatic login mechanisms like NTLM) the first is to use the information above and set an ACL for each client config that disallows access to anonymous users

Restricting access to unauthenticated users
<acl:acl id="authenticated">
  <entry type="deny">anonymous</entry>
  <entry type="allow">*</entry>
</acl:acl>

<client:config id="main">
  <acl>authenticated</acl>
  <title>My Super Client</title>
  <!-- other config content goes here -->
</client:config>

<client:config id="test">
  <acl>authenticated</acl>
  <title>My Test Client</title>
  <!-- other config content goes here -->
</client:config>

The other method is to use security.xml to ensure that the user is authenticated before they can even access the system.
This is done using the FilterSecurityInterceptor in security.xml. By default the FilterSecurityInterceptor supplied with Weave is configured to ensure that each user is at least an anonymous user, this is the lowest level of authentication and basically ensures that we at least have a user object to work with. Changing the objectDefinitionSource in the FilterSecurityInterceptor from IS_AUTHENTICATED_ANONYMOUSLY to IS_AUTHENTICATED_FULLY you cane ensure that the user is forced to authenticate (either via the login page or using non-interactive methods if they're setup) before they can get any further into the system.

Default authentication level in security.xml
<property name="objectDefinitionSource">
  <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /**=IS_AUTHENTICATED_ANONYMOUSLY
  </value>
</property>

This section can even be extended to provide different levels of default authentication for different client configurations, for example to ensure the user logs in to access main.html but allow anonymous access to everything else (this doesn't mean an anonymous user can access every other client config, just that that decision will be handled by the ACL's and not by security.xml) you could do the following.

Specific client access in security.xml
<property name="objectDefinitionSource">
  <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /main.html=IS_AUTHENTICATED_FULLY
    /**=IS_AUTHENTICATED_ANONYMOUSLY
  </value>
</property>

Client access with roles in security.xml

In addition to IS_AUTHENTICATED_FULLY and IS_AUTHENTICATED_ANONYMOUSLY you can also include roles that the user must have before they can access a given client configuration.

Role based access via security.xml
<property name="objectDefinitionSource">
  <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /external.html=ROLE_EXTERNAL
    /main.html=IS_AUTHENTICATED_FULLY
    /**=IS_AUTHENTICATED_ANONYMOUSLY
  </value>
</property>

Here it's assumed that when logging in the authenticated user will be granted the role ROLE_EXTERNAL, which would then allow them to access the /weave/external.html URL.

Note that the equivalent can be done in using ACL's attached to a client configuration.

Role based access via acl
<acl:acl id="external">
  <entry type="allow">ROLE_EXTERNAL</entry>
  <entry type="deny">*</entry>
</acl:acl>

<client:config id="external">
  <acl>external</acl>
  <title>My External Client</title>
  <!-- other config content goes here -->
</client:config>

There's one difference between using these above two methods that restrict access to a client configuration (assuming that in the security.xml version the client config doesn't also have an ACL attached, if it did then they're exactly the same), and that's when it comes to the display of the client list page.
The security.xml version will display the external client as being available to the user (because it doesn't have an ACL attached, meaning that the user won't fail to to pass the ACL checks for that particular client) but when the user attempts to open the page they'll either be asked to login, if they're an anonymous user or be denied access if they're not.

So this generally means that the ACL methods is more user friendly in an environment where the most of the authentication is being handled by Weave, whereas the security.xml methods can be more useful in environments where security is also being handled elsewhere and they user is never intended to see the listing page.

Filter chains

In addition to the FilterSecurityInterceptor objectDefinitionSource there's another location where the client URL can play a part in authentication in security.xml, and that's in the FilterChainProxy.

The filter chain proxy determines what steps will be taken when an browser request passes through the security system.
By default Weave is configured with two different filter chains, one for requests from the JavaScript code in the client and one for every other request. This is primarily done for error handling, where we want any errors to be presented to the user using a nice HTML page, but error in response to requests made by the JavaScript code should be in a format that it can interpret.

Default security filters
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
  <property name="filterInvocationDefinitionSource">
    <value>
      CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
      PATTERN_TYPE_APACHE_ANT
      /server/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,jsonExceptionTranslationFilter,filterInvocationInterceptor
      /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
    </value>
  </property>
</bean>

Here we can see the default filter chains, with the /server/* handling requests from the JavaScript code, and the /* chain handling everything else.

This list can be supplemented to perform different actions depending upon what filters a request should be processed by based on the URL of the request, and in this case we're talking about client configuration access URL's, so we can adjust the list to include a different filter chain for a different client

Default security filters
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
  <property name="filterInvocationDefinitionSource">
    <value>
      CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
      PATTERN_TYPE_APACHE_ANT
      /server/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,jsonExceptionTranslationFilter,filterInvocationInterceptor
      /internal.html=httpSessionContextIntegrationFilter,ntlmProcessingFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
      /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
    </value>
  </property>
</bean>

Here we've added the ntlmProcessingFilter to the filter chain for any requests to access /weave/internal.html.

Additional filter chains can be added for other client configurations.