A global singleton what contains information about the logged-in user.
Server reassign properties of this object each time endpoint
handler are executed
Implements EventEmitter and will emit login
event each time user logged in
or loginFailed
event with 2 parameters(isLocked, userName) when user UB authentication failed
const UB = require('@unitybase/ub')
const Session = UB.Session
# new Session ()
Members
# callerIP : string static
IP address of a user. May differ from IP address current user login from. May be empty if request come from localhost
# id : string static
Current session identifier
# pendingUserName : string static
Username for authentication in pending state
# tenantID : number static
ID of the tenant (for multi-tenancy applications). 0 if multi-tenancy is not enabled (see ubConfig.security.tenants
)
# uData : object static
Custom properties, defined in Session.on('login') handlers for logged-in user.
We strongly recommend to not modify value of uData outside the Session.on('login')
handler -
such modification is not persisted between calls.
Properties documented below are added by @unitybase/uba
and ``@unitybase/org` models, but other model can define his own properties.
Name | Type | Description |
---|---|---|
userID | number | Logged in user ID. The same as Session.userID. Added by |
login | string | Logged in username. Added by |
roles | string | Logged in user roles names separated by comma. In most case better to use uData.roleIDs array. Added by |
roleIDs | Array.<number> | Array or role IDs for logged-in user. Added by |
groupIDs | Array.<number> | Array or group IDs for logged-in user. Added by |
employeeShortFIO | string | Short name of the employee. Added by |
employeeFullFIO | string | Full name of the employee. Added by |
employeeID | number | Employee ID |
staffUnitFullName | string | |
staffUnitName | string | |
staffUnitID | number | permanent staffUnitID. Added by |
employeeOnStaffID | number | permanent employeeOnStaffID. Added by |
parentID | number | permanent staffUnitID parent. Added by |
parentUnityEntity | string | permanent staffUnitID parent entity type. Added by |
orgUnitIDs | string | all orgUnit's IDs as CSV string. Added by |
permanentOrgUnitIDs | string | all user orgUnit ID's permanent employeeOnStaffIDs in CSV. Added by |
permanentTreePath | string | mi_treePath of permanent position assignment for employee. Added by |
tempStaffUnitIDs | string | array temporary staffUnitIDs in CSV. Added by |
tempEmployeeOnStaffIDs | string | array of temporary employeeOnStaffIDs in CSV. Added by |
assistantStaffUnitIDs | string | array of assistant staffUnitIDs in CSV. Added by |
assistantEmployeeOnStaffIDs | string | array of assistant employeeOnStaffIDs in CSV. Added by |
allStaffUnitIDs | string | array of all (permanent + temporary + assistant) staffUnitIDs in CSV. Added by |
allEmployeeOnStaffIDs | string | array of all (permanent + temporary + assistant) employeeOnStaffIds in CSV. Added by |
tempPositions | string | stringified array of temporary position objects: {staffUnitID, employeeOnStaffID}. Added by |
assistantPositions | string | stringified array of assistant position objects: {staffUnitID, employeeOnStaffID}. Added by |
allPositions | string | stringified array of permanent + temporary + assistant position objects: {staffUnitID, employeeOnStaffID}. Added by |
ownOrganization | Object | An own organization. Added by |
# userID : number static
Logged-in user identifier (from uba_user.ID)
# userLang : string static
Logged-in user language. ==="" if no authentication running
# userRoleNames : string deprecated static
Logged-in user role names in CSV format. ==="" if no authentication running
To check user is a member of role use Session.hasRole('roleName') to get all roles as CSV string use `Session.uData.roles`, to get all roles IDs array - `Session.uData.roleIDs`
# userRoles : number deprecated static
Logged-in user role IDs in CSV format. ==="" if no authentication running
To check user is a member of role use Session.hasRole('roleName'); to get all roles as CSV string use `Session.uData.roles`, to get all roles IDs array - `Session.uData.roleIDs`
# zone : string static
Security zone for current session. In UB SE empty string
Methods
# _buildPasswordHash (uName: string, uPwdPlain: string) → string static
Build password hash based on user login and plain password Called by server during authorization handshake.
In case application need to use its own hash algorithm in can override this function inside model initialization. Maximum result length is 64 char. Result is case-sensitive
Return:
password hash to be stored/compared with uba_used.uPasswordHashHexa
# hasRole (roleName: string) → boolean static
O(1) checks if the current user is a member of the specified role(s)
If roles is array - at last one of passed roles.
const UB = require('@unitybae/ub')
const Session = UB.Session
if (Session.hasRole('accountAdmin')) {
console.debug('current user has accountAdmin role')
}
if (Session.hasRole(['Admin', 'Supervisor'])) { // equal to Session.hasRole('Admin') || Session.hasRole('Supervisor')
console.debug('current user is a member of `Admin` or/and `Supervisor` group')
}
# runAsAdmin (func: function) → * static
Call function as build-in admin
user. runAs*
functions allow maximum of 2 level depth of recursion.
Built-in "always alive"(newer expired) admin
session is always created when the application starts,
so this is very cheap method - it will not trigger Session.login event every time context is switched (Session.setUser and Session.runAsUser does)
Can be used in scheduled tasks, not-authorized methods, etc. to obtain a admin
Session context
Arguments:
func
: functionFunction to be called in admin context
# runAsUser (userID: number, func: function) → * static
Call function as a specified user. runAs*
functions allow maximum of 2 level depth of recursion.
New session will be created. Will fire login
event
# runInTenant (tenantID: number, func: function) → * static
Run a function in another tenant
Return:
Return result returned by the function
# setExpected2faSecret (secret: string) → boolean static
Set expected 2FA secret for non-system session. For sessions with non-empty 2FA secrets server deny execution of endpoints, what require authorization.
WARNING - should be called only inside Session.on('login') event handler. Otherwise, secret will not be persisted
Return:
true if success, false for system session
Arguments:
secret
: stringExpected 2FA secret
# setTempTenantID (newTenantID: number) → number static
Set new tenant ID, fire enterConnectionContext
for App object for all active
connections
Return original tenantID.
WARNING - original tenantID should be set back, better in try...finally block
Return:
original tenantID
Arguments:
newTenantID
: numbernew tenantID
const origTID = Session.setTempTenantID(5)
try {
// do something in new tenant ID context
} finally {
Session.setTempTenantID(origTID)
}
# setUser (userID: number, secretopt: string, persistopt: boolean) → string static
Create new session for userID
Return:
JSON string like answer on auth request
# switchLangForContext (newLang: string) → string static
Switch current execution context language. Can be used for example inside scheduler to create a report under admin but using target user language
Return:
Previous language for context
Arguments:
newLang
: string
Events
# login --> (req: THTTPRequest)
Fires just after user successfully logged-in but before auth response is written to client. Model developer can subscribe to this event and add some model specific data to Session.uData.
Since all uData content is passed to client and accessible on client via
$App.connection.userData(someCustomProperty
) do not add there a security sensitive data.
Standard models like @unitybase/uba
and @unitybase/org
are subscribed to this event and add
most useful information to the uData - Session.uData documentation.
Never override uData
using Session.uData = {...}
, in this case you delete uData properties,
defined in other application models.
Instead, define or remove properties using Session.uData.myProperty = ...
or use delete Session.uData.myProperty
if you need to un-define something.
Example below add someCustomProperty
to Session.uData. See also a real life example in @unitybase/org/org.js
// @ param {THTTPRequest} req
Session.on('login', function (req) {
const uData = Session.uData
uData.someCustomProperty = 'Hello!'
})
Arguments:
req
: THTTPRequestHTTP Request
# loginFailed --> (shouldLock: boolean, userName: string)
Fires in case auth
endpoint is called with authentication schema UB and userName is founded in database,
but password is incorrect.
If wrong password is entered more than UBA.passwordPolicy.maxInvalidAttempts
(from ubs_settings) times
user will be locked
Session.on('loginFailed', function(shouldLock, userName){
if (shouldLock)
console.log('User ', userName, 'entered wrong password and locked')
else
console.log('User ', userName, 'entered wrong password')
})
# registration --> ()
Fires in case new user registered in system and authentication schema support "registration" feature.
Currently, only CERT and UB schemas support this feature.
For CERT schema user registered means auth
endpoint is called with registration=1 parameter.
For UB schema user registered means 'publicRegistration' endpoint has been called and user confirmed registration by email otp.
Inside event handler server-side Session object is in INCONSISTENT state, and you must not use it!! Only parameter (stringified object), passed to event is valid user-relative information.
For CERT schema parameter is look like
{
"authType": 'CERT',
"id_cert": '<id_cert>',
"user_name": '<user_name>',
"additional": '',
"certification_b64": '<certification_b64>'
}
For UB schema parameter is look like
{
"authType": 'UB',
"publicRegistration": true,
userID,
userOtpData
}
Each AUTH schema can pass his own object as a event parameter, but all schema add authType
.
Below is a sample code for CERT schema:
Session.on('registration', function(registrationParams){
}
# secondFactorCodeReady --> (secret: string)
Fires ubConfig.security.secondFactor is enabled. Application must subscribe for this event and send a secret to user device (SMS, push notification, etc.)
Arguments:
secret
: string
# securityViolation --> (reason: string)
Fires in case of any security violation:
- user is blocked or not exists (in uba_user)
- user provide wrong credential (password, domain, encrypted secret key, certificate etc.)
- for 2-factor auth schemas - too many sessions in pending state (max is 128)
- access to endpoint "%" deny for user (endpoint name not present in uba_role.allowedAppMethods for eny user roles)
- password for user is expired (see ubs_settings UBA.passwordPolicy.maxDurationDays key)
- access to entity method is denied by ELS (see rules in uba_els)
const Session = require('@unitybase/ub').Session
Session.on('securityViolation', function(reason){
console.log('Security violation for user with ID', Session.userID, 'from', Session.callerIP, 'reason', reason);
})
Arguments:
reason
: string