Versions Compared

Key

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

Table of Contents
Requirements

High-level tasks:

...

Table of Contents
Requirements

High-level tasks:

  • mithril model and API changes - ave phone number, get services. Changes in concept user, party employee, party_users.
  • Change Create employee process - add 2nd factor phone number, add phone number verification step
  • Change approve employee process - two-step approval, resend sms
  • Change login process - step, resend sms, otp counter, block user after n logins failed
  • Existing users migration - move the mobile phone number to the 2nd factor
  • Mithril admin changes - show 2nd factor, block/unblock user
  • Introduce user endpoints to MIS

...

ColumnTypePurpose
iduuid
keyvarcharValue of factor (1 active 2FA for user) 
codevarcharValue of OTP
statusvarcharStatus (Dictionary: OTP_STATUS)
code_expired_attimestampTimestamp which OTP expired (now() + param from config)
attempts_countintegerCount of trying OTP authorization process
updateed_attimestamp

OTP states 

  • Dictionary: `OTP_STATUS`


    ValuePurpose
    NEWInitial status for newest OTP item. Ready to use in OTP verification process.
    VERIFIEDStatus for successful OTP verification process
    UNVERIFIEDStatus for unsuccessful OTP verification process
    EXPIREDExpired after OTP lifetime.
    CANCELED

    Status for manual admin action.


  • Status Chart for OTP
  • Transitions


    From
    Transition
    Result

    Created new OTPstatus = NEW
    status = NEWSuccseful OTP verifystatus = VERIFIED
    status = NEWUnsuccseful OTP verify afterexcess of count [param: OTP_ERROR_MAX] status = UNVERIFIED
    status = NEW[AUTO] Termination process after end of life-time OTP [param: OTP_LIFETIME]status = EXPIRED
    status = NEWAll OTP by `key` in status=`NEW` before creating new OTPstatus = CANCELED


Services specifications

1- WS.Create User (Modification) 
Status
colourGreen
titleDOne

Purpose

  • Add `is_blocked`, `block_reason` column in user entity
  • Add logic for create 2FA item for new user 

Logic WS

  1. Create user with this structure in `users.priv_settings`:

    Code Block
    {
        "login_error_counter": 0,
        "otp_error_counter": 0
    }

    and:

    1. is_blocked = FALSE
    2. block_reason = NULL


  2. .....
  3. After insert new user in `users`
  4. Get config-param `USER_2FA_ENABLED`
  5. If `USER_2FA_ENABLED` = TRUE
    1. Insert new record in `authentication_factors` with logical status = RESET
      1. user_id = $.user_id
      2. type = `SMS`
      3. factor = NULL
      4. is_active = TRUE
      5. update_at = now()

2- WS: DisableUser2FA (new EP) 
Status
colourGreen
titleDOne

APIary

PATCH mithril/api/users/{id}/actions/disable2fa 

Scope: `user:disable2fa`

Purpose

Disable 2FA for user (via Admin-console).

Request parameters

  • user_id

Logic WS

  • Validate token & scope
  • Validate user id & user status
  • Get active 2FA item for non-blocked user by $.user_id

    Code Block
    languagesql
    SELECT *
    FROM authentication_factors AS 2FA
    	INNER JOIN user AS U
    		ON 2FA.user_id = U.id
    WHERE 
    	U.id = $.user_id
    		AND U.is_active = TRUE
    		AND U.is_blocked = FALSE
    		AND 2FA.is_active = TRUE
    • If  exist 2FA item for user →  update 2FA item (set values):
      • 2FA.is_active = FALSE
      • 2FA.update_at = now()
  • Return 200
  • ...

Response

  • 200 if 2FA successful disable
  • 4xx in other case

...

POST mithril/api/tokens 

Scope: <NO SCOPE>

Purpose

Add handling logic for return different type of tokens by 2FA_Statuses

Request parameters

  • grant_type = "password"
  • email
  • password
  • client_id
  • scope = "app:authorize"

Logic WS

  • Validate token & scope
  • Check login exist
    • If login exist
      • Get user by $.email
      • Validate user.password = $.password
      • If invalid -  Update user (set values) by $.user_id
        • Increment

...

        • `users.priv_settings.login_error_counter` (+1)
        • If `users.priv_settings.login_error_counter`

...

Response

  • 201 if token successful create & return
  • 4xx in other case

...

APIary

Purpose

Logic WS

Response

        • > USER_LOGIN_ERROR_MAX
          • Blocked user - update user (set values) by $.user_id
            • is_blocked = TRUE
            • block_reason = "OTP verify attempts more then USER_LOGIN_ERROR_MAX"
            • updated_at = now()
  • Validate user status
  • Get active 2FA item for non-blocked user by $.user_id

    Code Block
    languagesql
    SELECT *
    FROM authentication_factors AS 2FA
    	INNER JOIN user AS U
    		ON 2FA.user_id = U.id
    WHERE 
    	U.id = $.user_id
    		AND U.is_active = TRUE
    		AND U.is_blocked = FALSE
    		AND 2FA.is_active = TRUE
    • If  exist 2FA active item for user
      • go to new process with 2FA (return 2fa_access_token + code 201)
    • If not exist 2FA active item for user
      • go to

...

      • standart process without 2FA (return access_token+ code 201)

Response

  • 201 if token successful create & return
  • 4xx in other case


7- WS: Create Approvals (Modification) 
Status
colourGreen
titledone

APIary

APIary

POST mithril/api/apps 

Scope: <NO SCOPE>

Purpose

Add handling logic for same type of tokens

Request parameters

  • token
  • client_id
  • redirect_uri
  • scope

Logic WS

  • Validate $.token
  • Get token by $.token
  • Extract token_type, user_id
  • Get user by user_id
  • Get active 2FA item for non-blocked user by $.user_id

    Code Block
    languagesql
    SELECT *
    FROM authentication_factors AS 2FA
    	INNER JOIN user AS U
    		ON 2FA.user_id = U.id
    WHERE 
    	U.id = $.user_id
    		AND U.is_active = TRUE
    		AND U.is_blocked = FALSE
    		AND 2FA.is_active = TRUE
    • If  not exist 2FA active item for user
      • If token_type = access_token - go to standard process create Approvals & return changed token (existing logic)
      • At any token_type - return 4xx error "" !!! TBD
    • If exist active 2FA
      • if token_type = access_token  - go to standard process create Approvals & return changed token (existing logic)
      • If token_type = 2fa_access_token - return 401 error

Response

  • 200 if token is correct & user grants approvals successful 
  • 4xx in other case



8- WS: Create OTP (New EP) 
Status
colourGreen
titledone

APIary

PATCH mithril/api/users/{id}/actions/sendOTP 

...

Create & Send new OTP item for user via current 2FA factor

Request parameters

  • user_id
  • token

Logic WS

  • Validate token (2fa_access_token) - ???? 
    • If invalid - return error 4xx 
  • Validate user id & user status
  • Get active 2FA item for non-blocked user by $.user_id

    Code Block
    languagesql
    SELECT *
    FROM authentication_factors AS 2FA	
    WHERE 
    	2FA.user_id = $.user_id
    		AND 2FA.is_active = TRUE
    • If not found - return 409 error "Not found 2FA data for user"
  • Extract type & factor from 2FA item for user
  • Invoke internal function `create OTP (key)`, for 2FA.type = SMS, with params:
    • key = 2FA.faсtor
    • Get result of call `create OTP()` as `OTP_value` 
  • Sending (delivery) OTP via channel communication 
    • for 2FA.type = SMS - via SMS gateway API
      • mobile phone = 2FA.factor
      • SMS text = OTP_value 
  • Return 200
  • ...

...

  • Processed OTP lists for $.key
    • Deactivate all active OTP items (NEW → CANCELED)
  • Create new OTP item
    • status = NEW
    • expired_at = now() + OTP_LIFETIME
    • value = generate number according OTP_LENGTH
    • updated_at = now()

Response

  • 200 if OTP successful create & send 
  • 4xx in other case

9- WS: Authorize via 2FA (New EP)
Status
colourGreen
titledone

APIary

PATCH mithril/api/users/{id}/actions/authorize2fa 

...

Verify OTP & prolongation authentication process (return access_token for getting approvals) .

Request parameters

  • user_id
  • otp
  • token

Logic WS

  • Validate token (2fa_access_token) - ???? 
    • If invalid - return error 4xx 
  • Validate user id & user status
  • Get active 2FA item for non-blocked user by $.user_id

    Code Block
    languagesql
    SELECT *
    FROM authentication_factors AS 2FA
    WHERE 
    	2FA.user_id = $.user_id
    		AND 2FA.is_active = TRUE
    • If not found - return 409 error "Not found 2FA data for user"
  • Extract type & factor from 2FA item for user
  • Invoke internal function `verify OTP (key, code)`, for 2FA.type = SMS, with params:
    • key = 2FA.faсtor
    • code = $.otp
  • Get result of call `verify OTP()`  
  • If result = VERIFIED
    • Update user (set values) by $.user_id
      • users.priv_settings.otp_error_counter = 0

    • Update 2fa_access_token (set `tokens.details.used`=true)
    • Create & return new access_token (as a existing standart process without 2FA)
    • Return 200
  • If result = UNVERIFIED
    • Update user (set values) by $.user_id
      • Increment `users.priv_settings.otp_error_counter` (+1)
    • If `users.priv_settings.otp_error_counter` counter` USER_OTP_ERROR_MAX
      • Blocked user - update user (set values) by $.user_id
        • is_blocked = TRUE
        • block_reason = "OTP verify attempts more then USER_OTP_ERROR_MAX"
        • updated_at = now()
    • return 401 error

...

  • Find 1 active OTP (status = NEW) for $.key
    • If not found - return 409 error "Not found active OTP" - ??? or 401 ?
    • If found -  increment  `attempts_count` (+1) for this OTP
      • If OTP.code = $.code - update OTP item:
        • OTP status  ( NEW → VERIFIED)
        • updated_at = now()
      • If (OTP.code <> $.code ) AND (OTP.attempts_count OTP_ERROR_MAX 
        • Update OTP item
          • status ( NEW → UNVERIFIED)
          • updated_at = now()

Response

  • 200 if OTP successful create & send 
  • 4xx in other case

10- WS: Change 2FA (New EP) 
Status
colourRed
titleTBD

APIary

Purpose

Logic WS

Response




11- PROC: [AUTO] Terminate OTP (new PROC) 
Status
colourGreen
titledone

...