Technical Specification Template

This is a template that can be used when writing technical specifications for development requirements. Keep in mind that this is a flexible template which can be adapted to the type of requirement. Here, an example has been used to illustrate how to fill in the template.

Request ID

72.1

Title of the

request

Security layer for IMIS API

Relates to

RFC 72

Submitted on

02/07/2018

Assessed on

 

Approved on

 

Status

Submitted
Assessed
Approved
Rejected
Processed
Implemented

Impact on costs

(man hours, man days)

 

Impact on schedule

 

Category of change

Minor
Major
Principal

Comments of vendor

 

 

 

Version history

Version

Date

Author

Revision

1.0

02/07/2018

DD (STPH)

First draft

1.1

10/07/2018

DD (STPH)

Added 2.3 JWT Payload information

Added user password change impact

 

1.             Requirement

1.1           Goals/Scope

The scope of this RFC is to increase the security of the IMIS API when used by any third party applications and thus not allowing access to API calls to not authorized users.

1.2           Background

The IMIS Web Services can be called by any Mobile or Web Client without prior need of a registered user. This is due to the fact that any API call is creating a new session on the server side and, even that a Validate_credential function exists, it doesn’t allows remembering the user whose credentials are validated. This represents a security threat for the all IMIS information system.

1.3           Assumptions

Assumes that the IMIS API is used by a registered user

1.4           User stories

#

User Story

Importance

Notes

1

As an IMIS administrator, I want to prevent unauthorized access to the information.

Must have

 

2

As a user, I want to get my personal API access token using my login credentials.

Must have

 

3

As a user, I want to access the API functions using my personal access token.

Must have

 

2.             Technical Specification

This technical specification will deal with the implementation of the authentication and the authorisation of the user to execute API calls. In order to assure this, the LOGIN API call and the calls to all other functions must be updated.

2.1           Authentication protocol

2.1.1       JWT Authentication

The IMIS API should use a JSON Web Tokens authentication.

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA. [https://jwt.io ]

JWTs consist of three parts separated by dots (.), which are:

Header.Payload.Signature

Therefore, a JWT typically looks like the following: xxxxx.yyyyy.zzzzz

Header

The header typically consists of two parts: the type of the token, which is JWT, and the hashing algorithm such as HMAC SHA256 or RSA.

In our case we will use:

{"alg": "HS256", "typ": "JWT"}

Then, this JSON is Base64Url encoded to form the first part of the JWT.

Payload

The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional metadata. There are three types of claims: reserved, public, and private claims.

Reserved claims: These are a set of predefined claims, which are not mandatory but recommended, thought to provide a set of useful, interoperable claims. Some of them are: iss (issuer), exp (expiration time), sub (subject), aud (audience), among others.

Notice that the claim names are only three characters long as JWT is meant to be compact.

Public claims: These can be defined at will by those using JWTs. But to avoid collisions they should be defined in the IANA JSON Web Token Registry or be defined as a URI that contains a collision resistant namespace.

Private claims: These are the custom claims created to share information between parties that agree on using them.

An example of payload we will use:

{"name": "[name of the user]", "role": "[role of the user]", "role": "[role of the user]"}

 

Optional, we could add an expiration time to increase the security. We will add claims in the token for each role of the user within the IMIS system. These roles will be then used to define the authorisation access to the API calls.

The payload is then Base64Url encoded to form the second part of the JWT.

Signature

To create the signature part you have to take the encoded header, the encoded payload, a private_key, the algorithm specified in the header, and sign that.

As we choose to use HMAC SHA256 algorithm, the signature will be created in the following way.

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), private_key)

The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn’t changed in the way.

2.1.2       How to use the JWT

In authentication, when the user successfully logs in using his credentials, a JSON Web Token will be returned and must be saved locally (typically in local storage, but cookies can be also used), instead of the traditional approach of creating a session in the server and returning a cookie.

Whenever the user wants to access a protected route, it should send the JWT, typically in the Authorization header using the Bearer schema. Therefore the content of the header should look like the following.

Authorization: Bearer <token>

This is a stateless authentication mechanism as the user state is never saved in the server memory. The server’s protected routes will check for a valid JWT in the Authorization header, and if there is, the user will be allowed.

2.1.3       Impact on the general architecture

There are some components that need to be updated in the general architecture (Figure 1) in order to implement the JWT authenticated API.

Figure 1. Composite structure for JWT authenticated API architecture

These components are:

·         The database for storing new private keys

·         The Web Application for creating and registering new private keys

·         The API for creating and validating the JWT

·         The different mobile or web clients to use the JWT

2.1.4       Impact on the database structure

In order to sign the token, we will generate a private_key for each registered User which will be saved on the server.

There are several possibilities:

·         The private_key can be generated on the user registration and used for all logins. This possibility allows multiple logins (multiple devices at a time).

·         The private_key can be regenerated on each login, but can be used only for the last login (only one device at a time).

·         The private_key can be generated for each login (multiple devices at a time) and all private_keys will be saved on a separated table in the database. This solution is more secure but it requests more time when calling the API on the validation part.

For IMIS authentication, we will use the first solution. This will impact:

·         the tblUsers table in the database by adding a column for the private_key

·         the User.aspx.vb page by generating the private_key and assigning it to the user

When generating the private_key value, a minimum length of 20 characters must be considered in order to satisfy encryption requirements.

Every time the user change the password, a new private key must be generated in order to invalidate any already provided JWT.

2.2           Authorisation protocol

Net Core supports for several types of authorisation mechanisms (ex. Simple, Role-based, Claims-based, and Policy-based).

For implementing the authorisation protocol, we will use the role-based authorization, as described in section 2.1.1. This is based on the Role claims from the JWT token stored on token creation.

For each API controller and/or action we will need to add the Authorize attribute with the Roles parameter (list of roles that has access to the controller/action).

[Authorize(Roles = "IMISAdmin")]

[Route("api/[controller]")]

public class ValuesController : Controller

{

        // GET api/values

        [Authorize(Roles = "EnrollmentOfficer")]

        [HttpGet]

        public IEnumerable<string> Get()

        {

            return new string[] { "value1", "value2" };

        }

}

2.3           JWT Payload information

In the authentication protocol we decided to use a JWT signed by user defined private key. For any API requests, the JWT have to be validated. This is only possible by knowing which user has requested this token, and to access his private key. We will use the “name” claim type to register the username in the token payload.

In the authorisation protocol, we chose to implement a Role-based authorisation protocol. Net core IdentityModel library provide out of the box authorisation mechanism based on the “role” claim type coming from the JWT. For each user’s role we will add a “role” claim with a string representing the role, the same strings used in the Authorisation protocol described in section 2.2.

For the expiration date we will provide a 5 (five) days limit. This value will be provided in the configuration file (appsettings.json) as an integer of number of days the token is valid (NOW + number of days).

Two additional claim types will be registered in the payload: the issuer and the audience. These values will be taken from the configuration file.

The JWT payload will have the following structure:

{

  "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": <username string>,

  "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": [

    <role string>,

    <role string>,

    …

  ],

  "exp": <expiration datetime>,

  "iss": <issuer string>,

  "aud": <audience string>

}

Example of a JWT payload for the Admin user:

{

  "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "Admin",

  "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": [

    "EnrollmentOfficer",

    "Manager",

    "Accountant",

    "Clerk",

    "MedicalOfficer",

    "SchemeAdmin",

    "IMISAdmin",

    "Receptionist",

    "ClaimAdmin",

    "ClaimContrib"

  ],

  "exp": 1533820230,

  "iss": "http://openimis.org ",

  "aud": "http://openimis.org "

}

 

2.4           Get API token

2.4.1       API /login diagram

 

Figure 2. Sequence diagram for API login call

2.4.2       API /login description

Feature

Specifications

Title

Validate credentials and generate token

Description

Creates and returns JWT token to use for the Authentication.  

URL

/login

Method

POST

Authentication

NONE

Request Body

{

"username": "[USERNAME]",

"password": "[PASSWORD]"

}

 

where:

·         USERNAME: string, required

·         PASSWORD: string, required

Response Codes and Body

200 - Success

{ "token": "[JWT_ACCESS_TOKEN]", "expires": "[Token_expiration_DateTime]" }

400 - Error in Request

{ "error": "The request body is invalid" }  

401 - Unauthorized

No body

 

2.5           API call

As presented in 2.1.2, every call that needs authentication has to add to the request header the Authorization tag with the token. This way, on the server side, the token is validated and the access to the resource is granted.

The next diagram presents an example of API call with JWT authentication.

2.5.1       API call diagram

2.5.2       API call description

Example of the specification for an API method:

Feature

Specifications

Title

Enter New Family

Description

Enters a new family/group and its head.

URL

/family

Method

POST

Authentication

JWT

Request Body

{

"village_code": "VILLAGE_CODE", // string, required

"insurance_number_of_head": "INSURANCE_NUMBER_OF_HEAD", // string, required

"other_name": "OTHER_NAME", // string, required

"last_name": "LAST_NAME", // string, required

"birth_date": "BIRTH_DATE", // date, required

"gender": "GENDER", // {male, female, other}, required

"poverty_status": "POVERTY_STATUS", // boolean, optional

"confirmation_type": "CONFIRMATION_TYPE", // tblConfirmationType, optional

"group_type": "GROUP_TYPE", // tblGroupType, optional

"confirmation_no": "CONFIRMATION_NO", // string, optional

"permanent_address_details": "PERMANENT_ADDRESS_DETAILS", // string, optional

"marital_status": "MARITAL_STATUS", // tblMaritalStatus, optional

"benefitiary_card": "BENEFITIARY_CARD", // boolean, optional

"current_village_code": "CURRENT_VILLAGE_CODE", // string, optional

"current_address_details": "CURRENT_ADDRESS_DETAILS", // string, optional

"profession": "PROFESSION", // tblProfession, optional

"education": "EDUCATION", // tblEducation, optional

"phone_number": "PHONE_NUMBER", // string, optional

"email": "EMAIL", // string, optional

"identification_type": "IDENTIFICATION_TYPE", // tblIdentification, optional

"identification_number": "IDENTIFICATION_NUMBER", // string, optional

"FSP_code": "FSP_CODE", // string, optional

}

Response Codes and Body

200 - Success

{ "familyID": "FAMILYID" }

400 - Error in Request

{"error": "ERROR_MESSAGE"}

401 - Unauthorized

No body

Error messages (400 status code)

1-Wrong format or missing insurance number of head

2- Duplicated insurance number of head

3- Wrong or missing permanent village code

4-Wrong current village code

5-Wrong or missing  gender

6-Wrong format or missing birth date

7-Missing last name

8-Missing other name

9-Wrong confirmation type

10-Wrong group type

11-Wrong marital status

12-Wrong education

13-Wrong profession

14-FSP code not found

 

Did you encounter a problem or do you have a suggestion?

Please contact our Service Desk



This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. https://creativecommons.org/licenses/by-sa/4.0/