XmlBlaster Logo

REQUIREMENT

security.development.serverPlugin.howto

XmlBlaster Logo


Type NEW
Priority HIGH
Status CLOSED
Topic HOWTO: Development of a Server Side Security Plugin
Des
cription

Introduction

As mentioned, the xmlBlaster security system is not and cannot be a completely implemented piece of software, which refers all aspects of security. The only thing it does, is to support the fundamentals as a framework.
In most cases, security functions require extra jobs (e.g. encryption - decryption) to be done on client side as well as on server side. Thus the framework can be divided into two main aspect: Server side and client side. But because of the fact, that a developer of an xmlBlaster client program doesn't need to use xmlBlaster client helper classes. Security functions cannot be guarenteed for client developers to be transparent. Thus a security plugin developer has to implement the server part, but it makes no sense to bind the developer to implement the client plugin, too. Although it is optional, I advice to do it.

Anyhow, this part of the xmlBlaster security howto describes only the server part.

Preparations

The first and most important step of developing a security plugin is to get the requirements straight. Therefore you should be able to answer following questions:

  • What is the general goal? What do you want to protect?
  • Which kinds of threads do you suppose?
  • Which of them do you want to prevent? (Possibly, the benefit won't justify the costs!)
  • What are the inherited security functions? (Authentication, authorization, ...)
  • What are the characteristics of the security functions? (E.g. a more or less strong encryption)
  • How do you want to implement these functions? (E.g. authentication via password or fingerprint)
  • Do you want to integrate existing services? (Kerberos, passwd-files, ...)
  • ...

In general, you must know what you want and how to achieve this. If so, there won't be a problem to integrate all that into the xmlBlaster. The only thing you have to do, is to implement the following interfaces:

  1. org.xmlBlaster.authentication.plugins.I_Manager
  2. org.xmlBlaster.authentication.plugins.I_Session
  3. org.xmlBlaster.authentication.plugins.I_Subject
  4. org.xmlBlaster.authentication.plugins.I_SecurityQos

What is the intention of the interfaces, methods and values?

org.xmlBlaster.authentication.plugins.I_Manager

The implementation of I_Manager is the central class loaded by the plugin loader. Therefore I_Manager extends I_Plugin. First of all, the methods defined in this interface have to be implemented to be able to load the plugin via the plugin loader. In a second step the methods of I_Manager must be implemented. Namely:

  • public I_Session reserveSession(String sessionId) throws XmlBlasterException
    This method will be called from xmlBlasted while a user (subject) tries to log on. The only parameter sessionId is a unique id for each session, generated by the xmlBlaster. The result is a session of an unauthenticated subject. In order to authenticate the subject, the xmlBlaster will call I_Session.init(String).
  • public void releaseSession(String sessionId, String qos_literal) throws XmlBlasterException
    This is the counter part of reserveSession(...). It's called while a logout e.g. to remove the session from the plugins internal session list (if it has one). The first parameter contains the id of the session. The second parameter is an optional qos literal. The plugin could use it e.g. to proof the authenticity of the source of the logout/disconnect request.
  • public I_Session getSessionById(String _id) throws XmlBlasterException
    The last method serves a way to determine a sessions security context via a textual session id. It must return the corresponding session, if it exists. Otherwise, it return null

org.xmlBlaster.authentication.plugins.I_Session

I_Session hides the implementation of session specific methods. Exactly one object exists per session. The follow methods have to be implemented:

  • public String init(String securityQos) throws XmlBlasterException
    init(...) is called as part of the login process. In the first step, the xmlBlaser reserves an I_Session-Object via I_Manager.reserveSession(String sessionId). If this happened without an exception, I_Session will be initialized using this method. The implementor may use it e.g. to authenticate subjects, log information to make subjects accountable for actions, etc.. The parameter securityQos is part of the login qos, provided by the client. It can be uses for exchange of crypto keys, transmission of information (e.g. user and password) for authemtication ... The result is a qos literal, too. It may be used e.g. to return keys, the session id, etc..
  • public String init(I_SecurityQos securityQos) throws XmlBlasterException
    This is basically the same as the last method. Its difference is only the type of the parameter securityQos. The qos has already been mapped to an object.
  • public I_Subject getSubject()
    Returns the corresponding subject.
  • public I_Manager getManager()
    Returns the responsible I_Manager.
  • public void changeSecretSessionId(String sessionId) throws XmlBlasterException
    Because the current implementation of org.xmlBlaster.authentication.Authenticate#connect(org.xmlBlaster.util.qos.ConnectQos, String) cannot provide a correct session id when an object of I_Session is instantiated, the id must be changed later. Therefore I_Session provides this method.
  • public String getSecretSessionId()
    Returns the id of this session.

org.xmlBlaster.authentication.plugins.I_MsgSecurityInterceptor

I_MsgSecurityInterceptor hides the implementation of message encryption and decryption. The follow methods have to be implemented:

  • public MsgUnitRaw importMessage(MsgUnitRaw msg, MethodName action) throws XmlBlasterException
    public String importMessage(String xmlMsg) throws XmlBlasterException
    public byte[] importMessage(byte[] content) throws XmlBlasterException
    The job of these methods is the import of messages. Therefore all incomming messages and message components (like qos without key and content) will be routed through one of these methods. In an implementation, they can be used to decrypt the information, verify a signature, log some information, and so on.
  • public MsgUnitRaw exportMessage(MsgUnitRaw msg) throws XmlBlasterException
    public String exportMessage(String xmlMsg) throws XmlBlasterException
    public byte[] exportMessage(byte[] content) throws XmlBlasterException
    These are the counterparts of of MsgUnitRaw importMessage(MsgUnitRaw msg, MethodName action) and String importMessage(String xmlMsg). Thus, they are the right location to encrypt, sign, log, etc. outgoing messages.

org.xmlBlaster.authentication.plugins.I_SecurityQos

Implementations of I_SecurityQos are simple wrappers for security related qos information. Both ways (XML to object and object to XML) have to be implemented. Following methods must be implemented:
  • public void parse(String xml) throws XmlBlasterException
    Parses the given XML literal and turns it into an object. Note: The XML literal doesn't represent a complete qos. It covers only the security related part of the qos, which is always enclosed by <securityService type='' version=''>...</securityService>. Example:
    A typical qos looks like this:
        <qos>
           ...
           <securityService type='htpasswd' version='1.0'>
              <![CDATA[
                 <user>fred</user>
                 <passwd>secret</passwd>
              ]]\>
           </securityService>
           ...
        </qos>
     
    The attributes of <securityService> are also mandatory. They are used by the qos-parser to determine the right plugin.
  • public void setUserId(String userId)
    Used to replace the userId.
  • public String getUserId()
    Has to return a previously set or parsed userId.
  • public void setCredential(String cred)
    This is used to set the credential. E.g. a password, signature, etc.
  • public String getPluginType()
    Must return the type of the plugin (e.g. 'htpasswd').
  • public String getPluginVersion()
    Must return the plugins version (e.g. '1.0').
  • public void toXml(String extraOffset)
    This is the counterpart of public void parse(String xml) throws XmlBlasterException. So it must serialize the data into an xml-stream. The purpose of the only parameter is to beautify the returned stream by indention.

org.xmlBlaster.authentication.plugins.I_Subject

Implementations of I_Subject user related attributes and methods. Following methods have to be implemented:
  • public boolean isAuthorized(String actionKey, String key)
    The intention of this method ist to check, if the subject (user) has the permission to perform a specific task. The first parameter describes the kind of the task (i.e. publish, subscribe, get, erase, ... see org.xmlBlaster.util.def.Constants. Whereas the second parameter describe whereon the task will be performed. Example: isAuthorized("publish", "aMessageKey");
    The example would check if the subject is permitted to 'publish' a message with the key 'aMessageKey'.
  • public String getName()
    getName has to return the subjects name.


How it all fits together - the passwd example

This chapter shows how it all fits together using probably the simples example. A plugin that logs some information and authenticates subjects via a Unix passwd file.


Initialization and connecting

Considered from the clients point of view, everything begins with establishing a xmlBlaster connection and the succeeding login. Therefore, the server requires a loginQos. This contains also security related information embedded in:

 <securityService type='passwd' version='1.0'>
    <![CDATA[
       ...
    ]]\>
 </securityService>
 

The server parses the qos end extracts this part including the securityService-tag. In a next step, the xmlBlaster tries to find a plugin with the type "passwd" and version "1.0" (PluginManager.getManager(...)) in its local cache respectively in the xmlBlaster.properties and will probably find there the following lines:

   Security.Server.Plugin[passwd][1.0]=org.xmlBlaster.authentication.plugins.passwd.PasswdManager   

If so, it will try to instanciate the class. Therefore PasswdManager has to implement the I_Manager interface which extends the I_Plugin interface. After creating an object, the objects construct will be call. That permits us i.e. to read config. data, open the passwd file and store user name and password as key-value pairs in a Hashtable, etc.. After this has taken place, Autheticate.connect(...) will call PasswdManager.reserveSession(...). It simply creates a new object of PasswdSession and stores it in a Hashtable. It is necessary to store each valid session, because getSessionById(...) may be called. Moreover, it permits us to implement some timeout behaviour.

   Hashtable sessions = new Hashtable();

   ...

   public I_Session reserveSession(String sessionId) {
      Session session = new Session(this, sessionId);
      synchronized(sessions) {
         sessions.put(sessionId, session);
      }

      return session;
   }
 

Autheticate.connect(...) will subsequently call init(...) on the just created object. This is the right place to identify the subject. Thus, it is necessary to get the PasswdSubject object which corresponds to the userId. If such an object doesn't exist, we know that the user is known and a "Access Denied" exception needs to be thrown. Otherwise the returned object will help us to authenticate the user.

But before that takes place, we need a method that serves the PasswdSubject objects. The best place to implement it is the PasswdManager:

   Hashtable allSubjects = new Hashtable();

   ...

   PasswdSubject getSubject(String _userId) {
      String       password;
      PasswdSubject subject;
      
      password = allSubjects.get(_userId);
      if (password==null) { // user is unknown
         subject = null
      }
      else {
         subject = new PasswdSubject(_userId, password); 
         // create new Object and fill it with user and password data 
      }

      return subject;
   }

Now, it is possible to check the users authenticity from PasswdSession.init(...) with PasswdSubject.authenticate(...).

   String username;
   String password;
   
   ...
   
   public boolean authenticate(String _passwd) {
      String encryptedPasswd = .... ; // generate unix encrypted passwd

      return (encryptedPasswd == password);
   }
 

The PasswdSession.init(...)-method itself:

   PasswdSubject subject = null;
   PasswdManager     mgr;
   String      sessionId;
   boolean authenticated = false; // successfully authenticated?

   // Constructor 
   public Session(PasswdManager _mgr, String sessionId) {
     mgr = _mgr;
     sessionId = sessionId;
   }

   public String init(String xmlQos_literal) throws 
      XmlBlasterException 
   {
      return init(new SecurityQos(xmlQos_literal));
   }

   public String init(I_SecurityQos securityQos) 
      throws XmlBlasterException 
   {
      authenticated = false;

      // Security function: IDENTIFICATION
      subject = mgr.getSubject(((SecurityQos)securityQos).getCredential()); 
      if (subject==null) 
         throw new XmlBlasterException("Access denied!"); // User unknown
      
      // Security Function: AUTHENTICATION
      authenticated = subject.authenticate(securityQos.getUserId());
      if (!authenticated)
         throw new XmlBlasterException("Access denied!"); // Wrong password

      return null; // we don't support a return qos (e.g. helpful for key-exchange)
   }
 

Finally Autheticate.connect(...) calls getSubject() on the just initialized I_Session object, before it returns and the user has logged on.


Publishing a message

Okay, so far so good. The user successfully connected to the xmlBlaster. But what happens if the user wants i.e. to publish a message?

After the user has called the servers publish method, it imports (e.g. decrypts, unseals, logs, ...) the message and checks the permission. It does this by calling the local method private MsgUnit checkMessage(SessionInfo sessionInfo, MsgUnit msgUnit, String action) throws XmlBlasterException, which fetches the security session context (the responsible I_Session instance) from the xmlBlaster session, which will be determined by the session id.
Now, the I_Session instance can be used to log, encrypt or unseal the message. In our implementation (PasswdSession) we don't support these features and return the message as it was given.
Additionally, I_Session will be used to get the Subject via getSubject(). This is necessary to check the permissions in a final step. Therefore, I_Subject.isAuthoriued(...) will be call. But because our driver doesn't support this, too, I_Subject.isAuthoriued(...) returns true in each case.
If these actions took place without problems, the xmlBlaster will continue with publishing the message. Otherwise it exits with an XmlBlasterException.


Other action like subscribtions, erasing messages, and so on follow the same pattern.


Conclusion

You've got a first impression what a developer of a security plugin has to do. The next step (if necessary) should be the examination of one of the existing security plugins.
Example
Java

Configure

NOTE: Configuration parameters are specified on command line (-someValue 17) or in the xmlBlaster.properties file (someValue=17). See requirement "util.property" for details.
Columns named Impl tells you if the feature is implemented.
Columns named Hot tells you if the configuration is changeable in hot operation.

See REQ security.introduction
See REQ security.htpasswd
See REQ security.ldap
See REQ SOCKET based SSL protection
See API org.xmlBlaster.authentication.plugins.I_Manager
See API org.xmlBlaster.authentication.plugins.I_Session
See API org.xmlBlaster.authentication.plugins.I_Subject
See API org.xmlBlaster.authentication.plugins.I_SecurityQos
See API org.xmlBlaster.authentication.plugins.I_MsgSecurityInterceptor

This page is generated from the requirement XML file xmlBlaster/doc/requirements/security.development.serverPlugin.howto.xml

Back to overview