SMODL Service Deployment Tutorial
ABSTRACT
This paper describes the runtime engine initialization process and the security limitations that can be applied on service method calls. The role validation mechanism which uses roles to support different user profiles is also discussed.
Understanding the SMODL service
The high-level composition of a SMODL service includes four items. The list below gives the reader a brief overview of each item.
SMODL model – is an XML document which represents a contract or a description of a SMODL service.
An application container which enables a network communication between a Web service client and a Web service implementation. The application initializes the runtime and serves client requests.
SMODL runtime engine ensures that the Web service implementation conforms to the service contract and as of version 1.1.5 applies roles-based security to each method call. The runtime also drives SOAP 1.1 and 1.2, XML-RPC as described in the specification and JSON-RPC (level 1) bindings for the service.
Web service implementation is an arbitrary service implementation in Java or PHP. However, it must comply with a SMODL model.
An initialization of the runtime engine
An implementor of the ISmodlServerRuntime interface represents the runtime engine. As any other runtime engine, the SMODL engine must be running in order for the SMODL service to execute. There is one-to-one correspondence between a SMODL service and a SMODL runtime engine. This means that if you need to run another SMODL service in the same container/application you need to create and run another runtime.
ISmodlServerRuntime interface represents the runtime manager which is responsible for runtime initialization. For a successful initialization the following sequence should occur in the application container:
The application binds the runtime with a SMODL service implementation by calling a corresponding method of the ISmodlServerRuntime interface
ISmodlServerRuntime.setImplementation (Object implementation);
Then it provides the runtime with a SMODL definition. During the initialization the runtime manager first looks up for the SMODL definition constant – _SMODL_DEFINITION – in the service implementation class. If the implementation is generated by Smodl Development Suite then the constant is set by default. An alternative approach to provide the runtime with the SMODL definition is by calling
ISmodlServerRuntime.setSmodlXml (String smodl);
Finally, the application calls the init() method
ISmodlServerRuntime.init ();
It worth to mention that the implementor of ISmodlServerRuntime calls service methods via
ISmodlServerRuntime.invoke (SmodlProtocol protocol, byte[] input);
where the protocol can be either SOAP, JSON or XML-RPC. The input parameter represents the actual service method call as received from a service client. This is the task of the application to extract a payload from the http-request and to pass it on as an input parameter to the invoke() method.
Role validation (optional)
The latest implementation of the SMODL runtime allows to control execution of SMODL service methods. During its initialization the runtime may get an object implementing the IRoleValidator interface. In this case the runtime checks if a service method can be called before in fact calling it. This is achieved by comparing the list of roles provided by the IRoleValidator and the list of roles assigned to a particular method. If there is an overlap between two sets of roles then the method can be called, otherwise an appropriate exception is thrown. Roles are just arbitrary strings. Since both IRoleValidator object and mapping between roles and methods are provided by the Web application component running the Web service, the execution of the service method is fully controlled by the Web application. To illustrate this we provide an example of the SMODL service implementation supporting role-based execution of methods.
Let's suppose a SMODL service deployment is implemented by extension of the SmodlHttpServlet. The extension alters the initialization of the SMODL runtime in order to add the mapping between service methods and roles. An implementation of the IRoleValidator interface is also provided.
securityService = new SessionSecurityService();
runtime.setRoleValidator(securityService);
runtime.setRoleMethodMapping(new String[] { "commonMethod" },
new String[] { "anonymous", "user" });
runtime.setRoleMethodMapping(new String[] { "userMethod" },
new String[] { "user" });
Code for the SessionSecurityService class will be displayed and explained further in the article. The above fragment of the runtime initialization sets mapping between the "commonMethod" method of the service and roles "anonymous" and "user" as well as the mapping between the "userMethod" method of the service and the "user" role. If the "user" role corresponds to an authenticated user of the service and the "anonymous" role corresponds to a non-authenticated user then the "userMethod" method can be only called by authenticated users while the "commonMethod" can be called by any service user. To achieve this we need a glue between roles and user authentication. The SessionSecurityService objects provides this glue.
public class SessionSecurityService implements ISecurityService, IRoleValidator {
private static ThreadLocal sessionHolder = new ThreadLocal();
public void userAuthenticated(String username) {
HttpSession session = sessionHolder.get();
session.setAttribute("username", username);
}
public boolean isSessionValid() {
HttpSession session = sessionHolder.get();
Object username = session.getAttribute("username");
if (username != null) {
return true;
}
return false;
}
public static ThreadLocal getSessionHolder() {
return sessionHolder;
}
public String getUsername() {
String result = null;
HttpSession session = sessionHolder.get();
result = (String)session.getAttribute("username");
return result;
}
public void userLoggedOff() {
HttpSession session = sessionHolder.get();
session.removeAttribute("username");
}
public String[] getRoles() {
return isSessionValid()? new String[] { "user" } : new String[] { "anonymous" };
}
}
An instance of this class stores a name of an authenticated user in the username property. This property is kept in the HttpSession object attached to a current thread. The Web application signalizes that the user is authenticated by calling the userAuthenticated() method. If the user logs out the Web application should call the userLoggedOff() method. Following the logic of implementation, the SessionSecurityService object returns role "user" if a user is authenticated and "anonymous" if a user is not authenticated in answer to the getRoles() method call.
To complete the example the extension of the SmodlHttpServlet should override the doPost method:
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
SessionSecurityService.getSessionHolder().set(request.getSession());
super.doPost(request, response);
SessionSecurityService.getSessionHolder().remove();
}
}
So in the beginning of each request the extension attaches the session object to the current thread and detaches it once the request was processed.