Layer Design
OpenXPKI tries to implement a MVC design (Model-View-Controller). The parts are defined as follows:
- Model
- The model is implemented by a workflow engine. This includes things like the configuration or the state handling.
- Controller
- The controllers are represented by the different workflow activities. Every activity can manipulate the state of a workflow including its properties.
- View
-
The view is represented by the user interfaces. I have to
admit though that the term is not fully correct. The
user interface consists of several layers to get better code:
- the service layer
- the messaging or serialization layer
- the transport layer
The major idea is to make the user interfaces much more flexible. It should be possible to use different transport protocol and it must also be possible to user other frontend language than Perl (e.g. PHP). The different layers are defined as follows:
- The service layer
This layer parses queries, executes necessary commands and build resulting answers. The format of the queries and answers are defined by the interface itself but in the native language (Perl). This means that a message can look like this:
my %msg = (COMMAND => "search_csr", PARAMS => {CN => "*Doe*"}, LIMIT => 20);The service layer defines a communication protocol but only on the level of native Perl messages. This means that a client send the above message but the answer is:
my %msg = (ANSWER_TYPE => "COMMAND", COMMAND => "GET_PKI_REALM", PKI_REALMS => {"root_ca" => "Our super root CA", "user_ca" => "User CA"});If this happens then the client must answer with root_ca or user_ca. Usually the next answer is the request for a login stack followed by the real login. Additionally the first answer can include a session ID. Like you see it is possible to implement a real communication protocol here. The only important thing is that we do not define any aspect of the serialization (the message representation) and the transport here.
Please note that it is highly important that every message contains a hash key SERVICE. This is necessary to signal the receiver of a message which service should be used after the deserialization of a message.
- The messaging or serialization layer
The service layer only defines how messages should look like in the used native language (Perl). This means a message is usually a hash. The serialization layer must produce now a plain text representation of this data. This can be a XML file or every other specially formatted text file. Please note that file does not mean that we write it on the disk. It is only a string in the memory.
This layer only has to serialize datastructures and to deserialize strings. It is not the job of this layer to distinguish between different message types. This is the job of the service layer which defines the real protocol. It is possible of course that some messages are serialized another way because they carry a special flag but this makes no difference for the interface usage and behaviour of this layer.
- The transport layer
The job of the transport layer is simple. It gets a plain text string and must bring this string to the other peer. The transport layer must not contain any knowledge about the communication protocol.
The minimum interface looks like this until now:
- new (incl. open)
- close
- write
- read
The problem is that this interface is fully synchronous. Actually I see no problem here but perhaps we must extend this interface in the future to support asynchronous mechanisms too. Nevertheless PKI is today mainly a synchronous business.
Reference Implementation
The practical handling of this protocol stack is really simple. The server gets an incoming connection. The first line of the incoming connection must be start simple. This signals the server which transport protocol must be used. After the initialization of the transport protocol the first message is read. The first message is the name of the serialization protocol. An example could be Simple. The server answers OK and the next message is parsed with the appropriate class OpenXPKI::Serialization::Simple. The parsed data structure must include a hash key SERVICE which announces the used service class.
Service Protocol
The first step is that we define a normal protocol workflow. If it is possible then we should express the whole protocol as one formula.
session ::= (init_session|continue_session).
use_session*.
(stop_session|nothing)
init_session ::= create_session_id.
select_pki_realm.
select_auth_stack.
login
use_session ::= request_command.
(
token_login*.
send_answer*.
)*.
(answer_complete|error)
stop_session ::= delete_session_id
This is a first abstraction for a session. Please note that this works for web clients which cut the connection everytime and for shell clients which are connected until they logout.
Serialization
Please see "perldoc OpenXPKI::Serialization::Simple" .
Transport
Please see "perldoc OpenXPKI::Transport::Simple" .
Example
Server View
- Established network connection
- Detected transport protocol
- Initialized transport protocol
- Send OK
- Read first message
- Detected serialization mechanism
- Initialized serialization mechanism
- Send OK
- Read service request
- Deserialize service request
- Initialize service with transport protocol and serialization mechanism
- Send OK
- Run service
- Service read next message
- Service performes the requested action
- Service prepares answer
- Service serializes (part) answer
- Service send answer
- Waiting for next message or terminating
Client View
- Connect server
- Send transport protocol identifier
- Read OK from server
- Send serialization mechanism
- Read OK from server
- Send requested service
- Read OK from server
- Creating query
- Serialize query
- Write query to transport layer
- Send serialized message
- Receive answer
- Deserialize answer
- Evaluate answer
- Continue with waiting for the next message (e.g. exports), sending a response or next query