Skip to content

Commit

Permalink
feat(oidc): session timeout finder logic
Browse files Browse the repository at this point in the history
  • Loading branch information
ficklephil committed Jul 13, 2020
2 parents 44b1fc6 + c071c64 commit 3f59af4
Show file tree
Hide file tree
Showing 3 changed files with 442 additions and 0 deletions.
91 changes: 91 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,94 @@ allows you to interactively build your commit. To do so, you can either type ```
## Alternative
You can still use ```git commit``` however in doing so you have to manually enforce the commit standard and type (please be aware
that your commit will still get linted and may fail otherwise).

## Get User Session Timeout

getUserSessionTimeout() allows a 3rd party application to calculate the Session Notification Timeout for a User,
based on their User Roles, and an array of Session Notification Timeouts, as defined
by the 3rd party service.

Feature example:

A W&P User on Manage Cases should have a Total Idle Time of 12 minutes,
and should show the Session Timeout Modal 3 minutes before the end of their session.

Whereas a Manage Organisation application user should have an Total Idle Time of 50 minutes,
and should show the Session Timeout Modal 10 minutes before the end of their session.

### Session Notification Timeouts shape

```
"sessionTimeouts": [
{
"idleModalDisplayTime": 3,
"pattern": "-dwpresponsewriter",
"totalIdleTime": 12
},
{
"idleModalDisplayTime": 3,
"pattern": "-homeoffice",
"totalIdleTime": 12
},
{
"idleModalDisplayTime": 10,
"pattern": "-solicitor",
"totalIdleTime": 50
},
{
"idleModalDisplayTime": 10,
"pattern": ".",
"totalIdleTime": 480
}
]
```

The Session Timeout configuration should be in PRIORITY ORDER, with the DEFAULT for
this application being the last item in the array.

The application DEFAULT is defined using the wildcard pattern ie '.'

User Roles shape

```
[
'pui-organisation-manager',
'pui-user-manager',
'pui-finance-manager',
]
```

### Steps to implement:

1. Include the node library within your package.json file ie.
```
yarn add @hmcts/rpx-xui-node-lib@latest --save
```
2. Import the function
```
import { getUserSessionTimeout } from '@hmcts/rpx-xui-node-lib'
```

3. Include the function call, and pass in the Users roles, and sessionTimeouts
as set by your team. @see above for shape inputs.

```
const sessionTimeout = getUserSessionTimeout(roles, sessionTimeouts)
```
4. Handle the returned object ie.
```
{
"idleModalDisplayTime": 3,
"pattern": "-homeoffice",
"totalIdleTime": 12
}
```

This object can be passed through to an UI. If the UI is in Angular,
the Angular UI can then implement the Timeout Notification Service and Timeout Notification Service Modal,
which the object generated by this Node API can be transfered into.

@see https://github.com/hmcts/rpx-xui-common-lib#timeout-notification-service
for an example of how to integrate the Timeout Notification Service and Timeout Notification Service Modal.

END
201 changes: 201 additions & 0 deletions src/common/util/userTimeout.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import {
anyRolesMatch,
DEFAULT_SESSION_TIMEOUT,
getUserSessionTimeout,
isRoleMatch,
RoleGroupSessionTimeout,
sortUserRoles,
} from './userTimeout'

describe('userTimeout', () => {
/**
* The Session Timeouts array is in PRIORITY ORDER ie. The FIRST Session Timeout object will be used
* if the FIRST Session Timeout regex pattern matches a User's role.
*
* If the first pattern is not matched, then the second one is tried, etc. If there are no matches
* then the final wildcard regex pattern is used - the DEFAULT.
*/
describe('getUserSessionTimeout()', () => {
it("should return the FIRST matching Session Timeout, if one of a User's Roles matches that Session Timeout's pattern.", () => {
const roles = ['pui-organisation-manager', 'pui-case-manager']

const roleGroupSessionTimeouts: RoleGroupSessionTimeout[] = [
{
idleModalDisplayTime: 5,
pattern: 'pui-',
totalIdleTime: 50,
},
{
idleModalDisplayTime: 2,
pattern: '.',
totalIdleTime: 12,
},
]

const usersSessionTimeout = getUserSessionTimeout(roles, roleGroupSessionTimeouts)

expect(usersSessionTimeout).toEqual(roleGroupSessionTimeouts[0])
})

it("should return the LAST MATCHING Session Timeout, if there are NO User Role's that match the previous reg ex patterns ie.", () => {
const DEFAULT_SESSION_TIMEOUT = [
{
idleModalDisplayTime: 2,
pattern: '.',
totalIdleTime: 12,
},
]

const roles = ['pui-organisation-manager', 'pui-case-manager', 'pui-finance-manager']

const roleGroupSessionTimeouts = [
{
idleModalDisplayTime: 5,
pattern: 'doesnotmatch',
totalIdleTime: 50,
},
// The last item is the default so that we can easily configure the default as IT will change on Go Live, informed by BA.
...DEFAULT_SESSION_TIMEOUT,
]

expect(getUserSessionTimeout(roles, roleGroupSessionTimeouts)).toEqual(DEFAULT_SESSION_TIMEOUT[0])
})

it(
'should return the SECOND matching Session Timeout, if the Session Timeout reg ex pattern DOES NOT match' +
'the FIRST Session Timeout pattern.',
() => {
const roles = ['pui-organisation-manager']

const roleGroupSessionTimeouts = [
{
idleModalDisplayTime: 5,
pattern: 'doesnotmatch',
totalIdleTime: 50,
},
{
idleModalDisplayTime: 10,
pattern: 'organisation',
totalIdleTime: 80,
},
{
idleModalDisplayTime: 2,
pattern: '.',
totalIdleTime: 12,
},
]

expect(getUserSessionTimeout(roles, roleGroupSessionTimeouts)).toEqual(roleGroupSessionTimeouts[1])
},
)

it('should return the DEFAULT_SESSION_TIMEOUT if the XUI team accidentally sets an incorrect default reg ex pattern.', () => {
const roles = ['pui-organisation-manager']

const roleGroupSessionTimeouts = [
{
idleModalDisplayTime: 6,
pattern: 'a-non-descript-pattern',
totalIdleTime: 60,
},
]

expect(getUserSessionTimeout(roles, roleGroupSessionTimeouts)).toEqual(DEFAULT_SESSION_TIMEOUT)
})

it(
'should return the DEFAULT_SESSION_TIMEOUT if the XUI team accidentally does not set a DEFAULT Session Timeout via the' +
'configuration.',
() => {
const roles = ['pui-organisation-manager']

const roleGroupSessionTimeouts: RoleGroupSessionTimeout[] = []

expect(getUserSessionTimeout(roles, roleGroupSessionTimeouts)).toEqual(DEFAULT_SESSION_TIMEOUT)
},
)

/**
* The following should never happen but the production code should be resilient to this edge case.
*/
it('should return the DEFAULT_SESSION_TIMEOUT if there are no User Roles.', () => {
const roles: string[] = []

const roleGroupSessionTimeouts = [
{
idleModalDisplayTime: 10,
pattern: 'organisation',
totalIdleTime: 80,
},
]

expect(getUserSessionTimeout(roles, roleGroupSessionTimeouts)).toEqual(DEFAULT_SESSION_TIMEOUT)
})

it(
'should give preference to Session Timeout patterns in a PRIORITY ORDER. A pattern nearer to the top of the list is' +
'higher priority.',
() => {
// Roles are sorted by sortUserRoles() which is a side effect within getUserSessionTimeout(), but we are
// showing the sorted roles here, as it's easier to understand what happens.
const roles = [
'caseworker',
'caseworker-divorce-financialremedy',
'caseworker-divorce-solicitor',
'caseworker-probate',
'caseworker-probate-solicitor',
'pui-user-manager',
'pui-finance-manager',
]

const roleGroupSessionTimeouts = [
{
idleModalDisplayTime: 10,
pattern: 'pui-user-manager',
totalIdleTime: 80,
},
{
idleModalDisplayTime: 20,
pattern: 'caseworker-probate',
totalIdleTime: 200,
},
]

expect(getUserSessionTimeout(roles, roleGroupSessionTimeouts)).toEqual(roleGroupSessionTimeouts[0])
},
)
})

/**
* Should sort the User's Roles alphabetically. Why? So that a priority order can be given to the Session Timeout +
* configuration list.
*
* Example: If we want a PUI Session Timeout.toBe( given preference over another Session Timeout it would be further
* up the Session Timeout Configuration list.
*/
describe('sortRolesAlphabetically()', () => {
it(
"should sort the User's Roles alphabetically, so that a priority order can be given to the Session Timeout" +
'configuration list.',
() => {
const roles = [
'caseworker-divorce-financialremedy',
'pui-user-manager',
'pui-case-manager',
'caseworker-probate-solicitor',
'caseworker',
'caseworker-probate',
'caseworker-divorce-financialremedy-solicitor',
'caseworker-divorce',
'pui-organisation-manager',
'pui-finance-manager',
'caseworker-divorce-solicitor',
]

const sortedRoles = roles.sort()

expect(sortUserRoles(roles)).toEqual(sortedRoles)
},
)
})
})
Loading

0 comments on commit 3f59af4

Please sign in to comment.