Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Background

Currently content update is done by the user who created it which creates problem and is complex in scenarios where an admin want to update content by retired user. There should be an easy way to allow users to update content at the same time it should have authentication.

Solution Approach 

approach 1 :

There should be a way to allow certain operations and for that we need to maintain master keys. These master keys would be created and stored through API by admin and would be used by anyone to bypass the current authentication mechanism which restricts some flow.

There should be APIs to create, fetch and verify the master key.

create API

No Format
nopaneltrue
POST /v1/masterkey/create

Request body : 

{
	request : {
		"channel" : "sunbird"
	}
}

Response body : (Success) 200

{
  "id": "api.masterkey.create",
  "ver": "v1",
  "ts": "2019-01-29 09:17:31:909+0000",
  "params": {
    "resmsgid": null,
    "msgid": "9db786d3-45c2-447d-b657-f9768da15652",
    "err": null,
    "status": "success",
    "errmsg": null
  },
  "responseCode": "OK",
  "result": {
		"key" : "1fb786d3-45c2-447d-b657-f9768da15348",
		"expiresOn":  604800
	}
}

Response body : (Error) 400

{
    "id": "api.masterkey.create",
    "ver": "v1",
    "ts": "2018-01-29 11:12:31:853+0000",
    "params": {
        "resmsgid": null,
        "msgid": "8e27cbf5-e299-43b0-bca7-8347f7e5abcf",
        "err": "KEY_EXISTS",
        "status": "KEY_EXISTS",
        "errmsg": "Key exists for given channel sunbird"
    },
    "responseCode": "CLIENT_ERROR",
    "result": {
        }
}

The key would be stored in DB with the argument passed

Table Structure

...

In addition a TTL will be put on the entry for a set time configured in properties file

get API

No Format
nopaneltrue
GET /v1/masterkey/{channel}

Response body : (Success) 200

{
  "id": "api.masterkey",
  "ver": "v1",
  "ts": "2019-01-29 09:17:31:909+0000",
  "params": {
    "resmsgid": null,
    "msgid": "9db786d3-45c2-447d-b657-f9768da15652",
    "err": null,
    "status": "success",
    "errmsg": null
  },
  "responseCode": "OK",
  "result": {
		"key" : "1fb786d3-45c2-447d-b657-f9768da15348",
		"expiresOn":  604800
	}
}

Response body : (Error) 404

{
    "id": "api.masterkey",
    "ver": "v1",
    "ts": "2018-01-29 11:12:31:853+0000",
    "params": {
        "resmsgid": null,
        "msgid": "8e27cbf5-e299-43b0-bca7-8347f7e5abcf",
        "err": "KEY_NOT_EXISTS",
        "status": "KEY_NOT_EXISTS",
        "errmsg": "Key does not exists for given channel sunbird"
    },
    "responseCode": "RESOURCE_NOT_FOUND",
    "result": {
        }
}

verify API

...

nopaneltrue

...

Problem Statement 1

What is the approach to generate the key?

Solution 1

Create JWT token with data passed upon. A JWT token will be created using secret key and below data 

  1. channel
  2. name
  3. description
  4. organisationId
  5. createdBy
  6. createdOn

Solution 2

Custom generated time based key.

Solution 3

Using keycloak to generate an verify token to be used as masterkey.


Pros and Cons

Key Generation ApproachPros

Cons

JWTno need to store the key in DB
Custommethod is available so negligible time consumingkey needs to be stored in db
Keycloakcomparatively faster to implement

no support for channel or organisation based key

key would expire based on keycloak configuration



Problem Statement 2

What are the APIs required to manage master keys?

API Specifications

Create API

name and channel / organisationId is mandatory.

URL: 

POST /v1/auth/masterkey/create

Headers:

  • Authorization
  • x-authenticated-user-token

Request Params:

param nametypedescription
channelStringchannel for which master key is applicable for, if not provided can be calculated from organisationId
nameStringconsumer name
organisationIdStringorganisationId for which master key is applicable for, if not provided can be calculated from channel

Response Params:

param nametypedescription
keyStringgenerated master key, mapped with the requested channel/organisationId and name

Errors:

status codeerror codeerror message
400INVALID_ORG_DATAGiven Organization Data doesn't exist in our records. Please provide a valid one.
400MANDATORY_PARAMETER_MISSINGMandatory parameter {channel/organisationId, name} is missing.
400PARAMETER_MISMATCHMismatch of given parameters: channel, organisationId.
400KEY_EXISTSKey exists for given channel {} and consumer {}


Sample Request and Response:

No Format
nopaneltrue
Request

{
	request : {
		"channel" : "sunbird",
		"keyname" : "1fb786d3-45c2-447d-b657-f9768da15348"
	}
}

Response body : (Success) 200

{
  "id": "api.masterkey.verify",
  "ver": "v1",
  "ts": "2019-01-29 09:17:31:909+0000",
  "params": {
    "resmsgid": null,
    "msgid": "9db786d3-45c2-447d-b657-f9768da15652",
    "err": null,
    "status": "success",
    "errmsg": null
  },
  "responseCode": "OK",
  "result": {
DikshaImplTeam",
		"orgId" : "01262366359399628812"
	}
}

Response body
:
(Error) 400

{
 
  "id": "api.auth.masterkey.create",
 
  "verresult": "v1",
    "ts": "2018-01-29 11:12:31:853+0000",
    "params": {
        "resmsgid": null,
        "msgid": "8e27cbf5-e299-43b0-bca7-8347f7e5abcf",
        "err": "INVALID_KEY",
        "status": "KEY_NOT_EXISTS",
        "errmsg": "Provided key for channel sunbird is invalid"
    },
    "responseCode": "CLIENT_ERROR",
    "result": {
        }
}

approach 2:

Previous approach is configured to create a master key only based on channel. This can be modified to create a master key based on organisation too. The changes we will have is we can pass type in the request too. The generated key will be stored with type and value as (channel, abc) or (orgId, "org01") 

No Format
nopaneltrue
Request body : 

{
	request : {
		"value" : "sunbird", 
		"type" : "channel"  //channel or orgId
	}
}

get API will be modified to include the type

GET /v1/masterkey/{type}/{value}

The verify API will include additional type parameter

No Format
nopaneltrue
{
	request : {
		"value" : "sunbird",
		"type" : "channel",
		"key" : "1fb786d3-45c2-447d-b657-f9768da15348"
	}
}

This also means that table will have another column "type" and it will be used to fetch key accordingly.

Other behavior remains same

approach 3:

In previous two approaches we are considering a master key which will be expired after certain duration. But it can be modified to include a refresh token which can be used to generate a new master key.  Note that refresh token has it's own expiry, post that it requires to create a new master key and refresh token by create API call.

The benefit of this is that it helps in mitigate leaking of master key by making the expiry duration of short intervals. 

No Format
nopaneltrue
POST /v1/masterkey/create

Request body : 

{
		"key" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaGFubmVsIjoic3VuYmlyZCIsIm5hbWUiOiJEaWtzaGFJ bXBsVGVhbSIsImNyZWF0ZWRCeSI6MTUxNjIzOTAyMiwiY3JlYXRlZE9uIjoxNTE2MjM5MDIyLCJleHBpcmVzT24iOjE1MTYyNDkwMjIsIm9yZ0lkIjoiMjM0NTY1NDU2In0.Cs5-FW7OHip6njkQvMP6zpIVB5Q-xLLgz_jnYW3zPOw"
	}
}


Verify API

URL:

POST /v1/auth/masterkey/verify

Headers:

  • Authorization

Request Params:

param nametypedescription
keyStringmaster key to verify 


Response Params:

param nametypedescription
channelStringchannel name related to master key
nameStringconsumer name
descriptionStringdescribes the purpose for master key
organisationIdStringorganisation Id mapped with key
createdByStringuserId of the person who created the key
createdOntimestamptimestamp when master key was created

Errors:

status codeerror codeerror message
400INVALID_KEYGiven master key is invalid
400MANDATORY_PARAMETER_MISSINGMandatory parameter key is missing.


Sample Request and Response:

No Format
nopaneltrue
Request

{
	request : {
		"channelkey" : "sunbirdeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaGFubmVsIjoic3VuYmlyZCIsIm5hbWUiOiJEaWtzaGFJ bXBsVGVhbSIsImNyZWF0ZWRCeSI6MTUxNjIzOTAyMiwiY3JlYXRlZE9uIjoxNTE2MjM5MDIyLCJleHBpcmVzT24iOjE1MTYyNDkwMjIsIm9yZ0lkIjoiMjM0NTY1NDU2In0.Cs5-FW7OHip6njkQvMP6zpIVB5Q-xLLgz_jnYW3zPOw"
	}
}

Response body : (Success)
200

{
  "id": "api.auth.masterkey.createverify",
  "ver": "v1",
  "ts": "2019-01-29 09:17:31:909+0000",
  "params"result": {
    		"resmsgidchannel": null,
    "msgid": "9db786d3-45c2-447d-b657-f9768da15652"sunbird",
    		"errname": null,
    "statusDikshaImplTeam": "success",
    "errmsg": null
  },
  "responseCode": "OK",
  "result": {		"description": "organisation content"
		"keyorganisationId" : "1fb786d3-45c2-447d-b657-f9768da15348",
		"expiresOn":  120,01262366359399628812"
  		"refreshTokencreatedBy": "3ab586d300dd6646-45c2be73-447d4fb0-b657b676-g9768da13730"
	}
}ccd01bda085e",
 request to regenerate the key need refresh token

{
	request : {
		"channelcreatedOn" : "sunbird"1548932815386,
		"refreshToken": "3ab586d3-45c2-447d-b657-g9768da13730" 	}
}

Response body (Success : 200)

{
  "id": "api.masterkey.create",
  "ver": "v1",
  "ts": "2019-01-29 11:17:31:909+0000",
  "params": {
    "resmsgid": null,
    "msgid": "9db786d3-45c2-447d-b657-f9769da15652",
    "err": null,
    "status": "success",
    "errmsg": null
  },
  "responseCode": "OK",
  "result": {
		"key" : "3gh686e3-45c2-447d-b657-b3364da84351",
		"expiresOn":  120,
		"refreshToken": "3ab586d3-45c2-447d-b657-g9768da13730"
	}
}

There would be a TTL on the refresh token, so as the entry gets removed after refresh token expiry and then it would require to create a fresh entry.

...


Delete API

URL:

POST /v1/auth/masterkey/delete

Headers:

  • Authorization
  • x-authenticated-user-token

Request Params:

param nametypedescription
channelStringchannel for which master key needs to be deleted
nameStringconsumer name
organisationIdStringorganisationId for which master key needs to be deleted

Response Params:

None

Errors:

status codeerror codeerror message
400MANDATORY_PARAMETER_MISSINGMandatory parameter {channel/organisationId, name} is missing.
400KEY_NOT_EXISTSKey does not exists for given channel {} and consumer {}


Sample Request and Response:

No Format
nopaneltrue
{Request 

"id": "api.masterkey.create",
  "ver": "v1",
  "ts": "2019-01-29 11:18:31:909+0000",
  "params": {
    "resmsgid": null,
    "msgid": "9db786d3-45c2-447d-b657-f9769da15652",
    "err": null,
    "status": "success",
    "errmsg": null
  },
  "responseCode": "OK",
  "result": {
		"key" : "3gh686e3-45c2-447d-b657-b3364da84351{
	request : {
		"channel" : "sunbird",
		"name" : "DikshaImplTeam",
		"expiresOnorgId":  30,
		"refreshToken": "3ab586d3-45c2-447d-b657-g9768da1373001262366359399628812"
	}
}

Response for expired key : (Error) 400

{

   "id": "api.masterkey.create",
    "ver": "v1",
    "ts": "2018-01-29 11:21:31:853+0000",
    "params": {
        "resmsgid": null,
        "msgid": "8e27cbf5-e299-43b0-bca7-8347f7e5abcf",
        "err": "INVALID_KEY",
        "status": "INVALID_KEY",
        "errmsg": "Either the key doesn't exists or it has been expired"
    },
    "auth.masterkey.delete",
  "responseCode": "CLIENT_ERROROK",

   "result": {
        	}
}

...


Problem Statement 3

What is the DB design for storing information about master keys?

approach 1:

JWT token Table Structure 

columntypedescription
channel*text
primary key as channel namekeytextmaster key generatedrefresh_tokentextrefresh token generatedkey_expirytimestamptime when current master key will be expiredcreatedbytextuser id of the user who created the entrycreatedontimestamptime when entry was created
consist user provide channel name
name*textprovided by user
organisationIdtextprovided by user or root org id mapped with channel
createdBytextuser id who created the master key
createdOntimestampcreated time
approach 2:

custom generated key

columntypedescription
channel*textconsist user provide channel name
name*textprovided by user
organisationIdtextprovided by user or root org id mapped with channel
keytextholds custom generated key
createdBytextuser id who created the master key
createdOntimestampcreated time


Problem Statement 4

How to use generated master key to bypass existing user authentication?

approach 1:
  • master key will be passed in X-authenticated-user-token
  • use an extra header (X-authentication-type) declaring the type of authentication as master( for master key and user for user authentication). 
approach 2:
  • extra header (X-authentication-master-key) to pass master key.
  • If above header is present it supersedes the user authentication 

Pros and Cons

Key Usage ApproachPros

Cons

X-authentication-typeIn future it can support additional authentication types