Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Task 2 — User Login and Access Control

Objective

Create a small user-access system.

The implementation must support:

  • user storage
  • user validation
  • authentication
  • password expiration
  • regular and streaming login modes
  • sector authorization
  • request authorization
  • IP-address authorization
  • failed-login tracking
  • automatic suspension

The validation system created in Task 1 must be used when new users are added.

User Model

Create a User structure containing:

Name
ID
Username
Password
PasswordValidUntil
PhoneNumber
Team
RegularLoginAllowed
StreamingLoginAllowed
AllowedSectors
AllowedRequests
AllowedIPAddresses
FailedLoginAttempts
Suspended

A possible Go representation is:

type User struct {
    Name                  string
    ID                    string
    Username              string
    Password              string
    PasswordValidUntil    time.Time
    PhoneNumber           string
    Team                  string
    RegularLoginAllowed   bool
    StreamingLoginAllowed bool
    AllowedSectors        []int
    AllowedRequests       []int
    AllowedIPAddresses    []string
    FailedLoginAttempts   int
    Suspended             bool
}

The exact field types may be adapted to the implementation.

Sector Request IDs

The system contains four sectors.

Sector 1

[]int{
    1, 2, 3,
    10, 11, 12, 13,
    20, 21, 22,
    30, 35,
    45, 46,
    50,
}

Sector 2

[]int{
    100, 101, 102, 103, 104, 105, 106,
    110, 111, 112, 113,
    115, 116, 117,
    120,
}

Sector 3

[]int{
    200, 202, 204, 206, 208,
    210, 212, 214, 216,
    220, 240,
}

Sector 4

[]int{
    302, 304, 306, 308,
    320, 325,
    350, 360, 370, 390, 399,
}

Allowed Sectors

A user may be configured for:

all
1
2
3
4

A typed representation is preferred over mixing strings and integers.

For example, an implementation may use:

type SectorAccess struct {
    All     bool
    Sectors []int
}

User Store

Create a custom user store containing three users.

You may choose the actual attribute values.

For example:

type UserStore struct {
    Users []User
}

When a new user is added:

  1. validate all required string attributes using Task 1
  2. validate the sector configuration
  3. validate request IDs
  4. validate allowed IP addresses
  5. validate password-expiration data
  6. reject the user when validation fails

LoginData

Create a structure named:

LoginData

with the following attributes:

LoginType
ReqID
Username
UserPass
AllowedAddress

For example:

type LoginData struct {
    LoginType      string
    ReqID          int
    Username       string
    UserPass       string
    AllowedAddress string
}

Login Types

The user model distinguishes:

regular login
streaming login

A typed representation is recommended.

For example:

type LoginType string

const (
    LoginTypeRegular   LoginType = "regular"
    LoginTypeStreaming LoginType = "streaming"
)

Login Processing

Create a function that receives:

LoginData

and verifies the login attempt against the user store.

Conceptually:

CheckLogin(store, loginData)

Login Validation Order

A login attempt should verify relevant conditions such as:

  1. user exists
  2. user is not suspended
  3. password is correct
  4. password has not expired
  5. requested login type is allowed
  6. source IP address is allowed
  7. request ID is allowed
  8. the request belongs to an allowed sector

All applicable authorization rules must be satisfied.

Successful Login

On successful login, return information containing:

Name
Username
Team
AllowedSectors
AllowedRequests

A structured result can be used:

type LoginSuccess struct {
    Name            string
    Username        string
    Team            string
    AllowedSectors  []int
    AllowedRequests []int
}

Failed Login

A failed login must return a list of errors.

For example:

type LoginError struct {
    Code    string
    Message string
}

The result may contain:

[]LoginError

rather than only one error.

Required Failure Scenarios

Create examples for the following failures.

Bad Username or Password

The submitted credentials do not match a valid user.

Expired Password

The current UTC time is later than:

PasswordValidUntil

Request ID Not Allowed

The requested:

ReqID

is not included in the user’s allowed request IDs.

IP Address Not Allowed

The submitted address is not contained in:

AllowedIPAddresses

Streaming Login Not Allowed

A streaming login was requested but:

StreamingLoginAllowed == false

Suspended User

The account is already suspended.

Failed Login Counter

Every failed login attempt must update:

FailedLoginAttempts

according to the suspension rule.

The original task states:

USER is suspended on second failed login attempt.

Therefore, once the failed-login count reaches:

2

set:

Suspended = true

Suspension Rule

Conceptually:

first failed login
    ↓
FailedLoginAttempts = 1
Suspended = false

second failed login
    ↓
FailedLoginAttempts = 2
Suspended = true

Further login attempts must fail because the user is suspended.

Important Security Behavior

A failed login caused by an unknown username cannot update the state of a user that does not exist.

For an existing username with invalid authentication or authorization data, the implementation must define which failure types increment the failed-login counter.

The original task does not distinguish authentication failures from authorization failures for this purpose.

Therefore, the implementation must document its chosen policy.

One reasonable interpretation is:

credential failures increment FailedLoginAttempts
authorization failures return errors without incrementing credential-failure state

but this behavior is an implementation decision beyond what the original source explicitly specifies.

Successful Login and Counter Reset

The original task does not state whether a successful login resets:

FailedLoginAttempts

Do not silently assume a reset rule.

If the implementation adds one, document it explicitly.

Request-to-Sector Relationship

A request ID belongs to one of the four defined sectors.

A login request should satisfy both:

the user is allowed to access the request ID

and:

the user is allowed to access the sector containing that request ID

Validation Integration

When users are created, use Task 1 to validate attributes such as:

  • Name
  • ID
  • Username
  • Password
  • PasswordValidUntil
  • PhoneNumber
  • AllowedIPAddresses

The appropriate validation type should be selected for each field.

Testing

Create at least:

  • one successful login
  • bad username or password
  • expired password
  • unauthorized request ID
  • unauthorized IP address
  • forbidden streaming login
  • suspended-user login
  • first failed login
  • second failed login causing suspension

Implementation Notes

Keep the responsibilities separated.

A useful design is:

User validation
      ↓
User store
      ↓
Authentication
      ↓
Authorization
      ↓
Account-state update
      ↓
Structured response

Avoid implementing every rule inside one large conditional block.

Scalionix Docs

Keyboard Shortcuts

Navigate the documentation without leaving the keyboard.
Navigation
Previous subject
←
Next subject
→
Previous subsection
Alt + ↑
Next subsection
Alt + ↓
Interface
Documentation Home
Ctrl + Enter
Search
Alt + Q
Open shortcuts
?
Close dialog
Esc
Scalionix Docs

Search Documentation