Dwarf Server Framework 1.3.1

Console Command Tutorial


Content

 

Introduction

This tutorial will show you how to do the following:


Creating a new console command

A server console is an interface for managing Dwarf-based applications. A console command is pluggable service which can be invoked locally by hand through the interactive command prompt, or remotelly through a network connection. All console commands must extend the Command abstract class and may be added to any server instance, but typically the Console one. A simple XML-based configuration of a server application with the interactive console and a couple of commands may look like this:

<configuration security="on" debug="auth" trace="" verbose="off">
  <service classbase="SK.gnome.dwarf" class=".main.MainServer" name="Main Server">
    <set name="logFacility">server</set>
    <set name="authFacility">Dwarf</set>

    <!-- CONSOLE -->
    <service class=".main.Console" name="Console">
      <set name="prompt">true</set>

      <!-- COMMANDS -->
      <service class=".main.cmd.HelpCmd" name="help"/>
      <service class=".sample.AuthCmd" name="auth">
        <set name="authFacility">AuthCmd</set>
      </service>
      <service class=".main.cmd.PolicyCmd" name="policy"/>
      <service class=".main.cmd.ShutdownCmd" name="shutdown"/>
    </service>

    <!-- ...rest of services... -->

  </service>
</configuration>

Let's say we need a console command named AuthCmd for testing the user authentication and authorization. Our new interactive command will accept the username, password and permission string arguments. At least the first one must be specified to invoke the command successfuly. The command will perform the following actions depending on the number of its arguments:

See the complete source code of the AuthCmd class and consult the following explanation.

In order to create the AuthCmd we must extend the Command abstract class mentioned above and add the necessary authentication and authorization testing code to it.

For authentication we use the login method inherited from the GenericService class. This method just routes the call to the default authentication adapter configured for the whole application. There is only one authentication adapter implementation available in the base Dwarf framework - the JAASAuthenticator class, which utilizes the Java Authentication and Authorization Service's pluggable login modules. We configure and use this service to do the actual authentication job. (The details of this will be covered later.)

For authorization we use the CheckPermissionAction object instance passed in to the javax.security.auth.Subject.doAs static method. The checked permission must be an instance of the SamplePermission class, which was created just for this single purpose.


Configuring login modules

In the next step we must tell the login mechanism that we are going to use a new custom login configuration in addition to the existing ones, probably specified by the other services. We do this by adding a new entry to the default login configuration file:

<configuration security="on" debug="auth" trace="" verbose="off">
  <property name="java.security.policy">file:conf/samples/dwarf/java.policy</property>
  <property name="java.security.auth.policy">file:conf/samples/dwarf/jaas.policy</property>
  <property name="java.security.auth.login.config">file:conf/samples/dwarf/jaas.config</property>
  ...

The mentioned new entry in the given jaas.config file will be:

AuthCmd {
   SK.gnome.dwarf.auth.login.PlaintextLoginModule required ident="true" file="conf/samples/dwarf/users.properties";
};

You can view the full sample "jaas.config" file used for this tutorial here. Please note that the login configuration is named "AuthCmd", therefore we must set a different value for the command's authentication facility, represented by the "authFacility" attribute in the XML-based configuration. Otherwise it would use the global "Dwarf" authentication facility, inherited from the main server object.

An alternative (and probably more flexible) way is to leave the original login configuration file intact and install the additional login configuration via the corresponding security property:

<configuration security="on" debug="auth" trace="" verbose="off">
  <property name="java.security.policy">file:conf/samples/dwarf/java.policy</property>
  <property name="java.security.auth.policy">file:conf/samples/dwarf/jaas.policy</property>
  <property name="java.security.auth.login.config">file:conf/samples/dwarf/jaas.config</property>

  <!-- ADDITIONAL LOGIN CONFIGURATION COMES HERE -->
  <property type="security" name="login.config.url.">file:conf/samples/dwarf/cmd/jaas.config</property>
  ...

This sets the "login.config.url.n" security property to the given URL. The postfix number n after the property name is automatically adjusted to the first available number in the ordered sequence.

Please note that the login configuration in this example uses the PlaintextLoginModule class, which is a simple login module based on a plaintext user database. This module accepts an optional key ident which allows the module to not authenticate the user but to check only whether the user exists in the user database. By passing either an username only or both the username and the password to the login method via an appropriate callback handler we specify whether the given user should be identified only or fully authenticated.

Note also that the first argument to the login method specifies an authentication facility to be used for the login operation. If we would use the two-argument inherited login method instead, the string returned by the service's getAuthFacility method would be used to identify the desired login configuration instead. The authFacility attribute value is inherited from the containing parent service by default, but it can be changed via the setAuthFacility method, too.

Having configured the login modules we are able now to try the first two forms of the AuthCmd command - either with the single username argument or with both the username and the password arguments. But the third form - checking the custom permissions - would always return a negative result. In order to make the permission check working as expected we need to grant some subject-based permissions to user(s) for the given AuthCmd service.


Configuring subject-based permissions

The subject-based policy grants a set of permissions to the given code source and a subject.

Dwarf uses a special form of subject - it is a combination of principal representing the service and one or more principals representing the user, who uses the service. The service is represented by an instance of the ServicePrincipal class with the name equal to the service's full name as returned from its getFullName method. The user is represented by an instance of either the UserPrincipal class or the RolePrincipal class. The typical subject-based policy entry may look like this:

  grant principal SK.gnome.dwarf.auth.ServicePrincipal "Main Server/Console",
  principal SK.gnome.dwarf.auth.RolePrincipal "administrators"
  { permission SK.gnome.dwarf.auth.ServicePermission "executeCommand.*";
  };

It means that the permission ServicePermission "executeCommand.*" is granted to any authenticated user, which is a member of the administrators role, if the user has been authenticated by a service "Main Server/Console". The single wildcard character "*" (without quotes) may be used to represent any existing principal.

Let's say now that the AuthCmd instance is named "auth". If we want to grant the permission SamplePermission "perm1" to the user admin for this command, we should add the following policy entry:

  grant principal SK.gnome.dwarf.auth.ServicePrincipal "Main Server/Console/auth",
  principal SK.gnome.dwarf.auth.UserPrincipal "admin"
  { permission SK.gnome.dwarf.sample.SamplePermission "perm1";
  };

(Note: The JDK implementation requires that this permission must be included also in the standard security policy. Since the default sample policy file in Dwarf grants all permissions to all class libraries, this requirement is fulfilled automatically.)

But how to tell the Java security manager that we are going to use a new set of subject-based permissions in addition to an existing subject-based policy, probably specified by the other services? We do it by adding the new subject-based permissions to the subject-based policy file. In the default sample configuration it is the "conf/samples/dwarf/jaas.policy" file:

<configuration security="on" debug="auth" trace="" verbose="off">
  <property name="java.security.policy">file:conf/samples/dwarf/java.policy</property>
  <property name="java.security.auth.policy">file:conf/samples/dwarf/jaas.policy</property>
  <property name="java.security.auth.login.config">file:conf/samples/dwarf/jaas.config</property>
  ...

You can view the full sample policy file with the new added permissions here.

An alternative (and probably more flexible) way is to leave the original subject-based policy file intact and install an additional policy file via the correspondent security property:

<configuration security="on" debug="auth" trace="" verbose="off">
  <property name="java.security.policy">file:conf/samples/dwarf/java.policy</property>
  <property name="java.security.auth.policy">file:conf/samples/dwarf/jaas.policy</property>
  <property name="java.security.auth.login.config">file:conf/samples/dwarf/jaas.config</property>

  <property type="security" name="login.config.url.">file:conf/samples/dwarf/cmd/jaas.config</property>

  <!-- ADDITIONAL SUBJECT-BASED POLICY COMES HERE -->
  <property type="security" name="auth.policy.url.">file:conf/samples/dwarf/cmd/jaas.policy</property>
  ...

This sets the "auth.policy.url.n" security property to the given URL. The postfix number n after the property name is adjusted automatically to the first available number in the ordered sequence.

Warning: installing of the additional policy via the system security property as described above may depend on the particular JDK implementation and may not work on your platform as expected.

You can view the full additional policy file here.


Running the application

Now it is time to execute the application and try the new command. All sample configuration files for this tutorial can be found in the "conf/samples/dwarf/cmd/" subdirectory of the Dwarf installation. Run one of the executing scripts with the location of the main configuration file as the single argument:

On Windows system:

 C:\Dwarf> run.bat conf/samples/dwarf/cmd/main.xml

On Unix system:

 localhost:/usr/dwarf# ./run.sh conf/samples/dwarf/cmd/main.xml

While the application is running you can press Enter at the command prompt to get into the server management console. The help command will give you a list of the available commands. It should list also the auth command, which we have just created and configured.

By playing with the various combinations of command arguments you can examine whether the users are authenticated and permissions are granted to them as desired. Refer to the "conf/samples/dwarf/users.properties" file for the list of available sample users.
Try to change the subject-based policy several times and see the results. You do NOT need to restart the server after changing the subject-based policy file - use the policy command for refreshing the policy instead. However, you MUST restart the server if you add or remove either a login configuration URL or a subject-based policy URL via the security property.

Seamlessly integrated subject-based authorization together with the centralized and application-independent authentication via the pluggable login modules are one of the great advantages of the Dwarf Server Framework.

 

Return to the main page.


Copyright (c) 1999-2005, Gnome Ltd. All rights reserved.