Skip to main content

Session

Overview

PortDIC provides an operator session management handler (ISessionHandler) for SEMI E30 compliant systems. It handles user authentication (login/logout), role-based access control, and Control State transitions (Offline / Local / Remote). Passwords are hashed with bcrypt via the Rust FFI layer.

The Session handler is a singleton — one instance is shared across all [Auth]-decorated classes in the application.


Quick Setup

1. Define an Auth class

using Portdic;

[Auth]
[Package("security")]
public class SecurityPackage
{
[SessionHandler]
public ISessionHandler Session { get; set; }

[Preset]
void Init()
{
// Register users on startup
Session.AddUser("admin", "admin123", "Administrator", roleLevel: 3);
Session.AddUser("operator", "op_pass", "Operator", roleLevel: 1);
Session.AddUser("viewer", "view_pass", "Viewer", roleLevel: 0);

Session.OnSessionChanged += OnSessionChanged;
Session.OnAuthenticationFailed += OnAuthFailed;
Session.OnSessionTimeout += OnTimeout;
}

private void OnSessionChanged(SessionEventArgs e)
{
Console.WriteLine($"[Auth] {e.ChangeType}: user={e.UserId}, role={e.RoleLevel}");
}

private void OnAuthFailed(AuthFailureEventArgs e)
{
Console.WriteLine($"[Auth] Failed: user={e.AttemptedUserId}, reason={e.FailureReason}, count={e.FailureCount}");
}

private void OnTimeout(TimeOutEventArgs e)
{
Console.WriteLine($"[Auth] Timeout: user={e.UserId}, idle={e.InactivityDuration}");
}
}

2. Register and run

Port.Add<SecurityPackage>("security");
Port.Run();

Authentication

// Login
bool ok = Session.Login("operator", "op_pass");
if (!ok)
Console.WriteLine("Login failed");

// Check current session
Console.WriteLine(Session.IsAuthenticated); // true
Console.WriteLine(Session.CurrentUserId); // "operator"
Console.WriteLine(Session.CurrentRoleLevel); // 1
Console.WriteLine(Session.LoginTime); // DateTime

// Logout
Session.Logout();

// Change password (verifies current password first)
Session.SetPassword("operator", "op_pass", "new_secure_pass");

// List all registered users
List<string> users = Session.GetUsers();

Role-Based Access Control

Role levels are plain integers — higher values grant more privileges.

Role LevelTypical RoleCapabilities
0ViewerRead-only access
1OperatorCan switch to Local control
2EngineerCan switch to Remote control
3AdministratorFull access
// Check role before allowing an action
if (Session.CurrentRoleLevel >= 2)
{
// allowed for Engineer and above
}

// Get session info programmatically
int role = Session.GetCurrentSessionRole();
string uid = Session.GetCurrentSessionUserID();
string name = Session.GetCurrentSessionUserName();
DateTime loginTime = Session.GetCurrentSessionLoginTime();

Control State (SEMI E30)

Transitions between Offline / Local / Remote are authorized against the current user's role level. The minimum required role level per state is enforced by the Rust FFI layer.

// Attempt to transition the equipment control state
bool granted = Session.ReassignControlState(ControlState.Remote);
if (!granted)
Console.WriteLine("Insufficient role level for Remote control");
ControlStateDescriptionTypical Minimum Role
OfflineEquipment not accepting remote commands
LocalLocal operator control1
RemoteHost system control2

API Reference

Attributes

AttributeTargetDescription
[Auth]ClassMarks the class as authentication-aware
[SessionHandler]PropertyInjects the shared ISessionHandler singleton
[Preset]MethodCalled after injection to configure the handler

Properties

PropertyTypeDescription
CurrentUserIdstringLogged-in user ID, or "" if not authenticated
CurrentRoleLevelintRole level of the logged-in user, or -1 if not authenticated
LoginTimeDateTimeTimestamp when the current user logged in
IsAuthenticatedbooltrue if a user is currently logged in

User management methods

MethodReturnsDescription
AddUser(userId, password, name, roleLevel)boolRegister a new user. Password is bcrypt-hashed
Login(userId, password)boolAuthenticate a user
Logout()Log out the current user
SetPassword(userId, currentPassword, newPassword)boolChange a user's password (verifies current password)
GetUsers()List<string>Return all registered user IDs

Session query methods

MethodReturnsDescription
GetCurrentSessionRole()intRole level of the current session, or -1
GetCurrentSessionUserID()stringUser ID of the current session, or ""
GetCurrentSessionUserName()stringDisplay name of the current user, or ""
GetCurrentSessionLoginTime()DateTimeLogin timestamp, or DateTime.MinValue

Control state

MethodReturnsDescription
ReassignControlState(ControlState)boolAttempt a control state transition (role-checked)
ControlStateValueDescription
OfflineEquipment offline
LocalLocal control mode
RemoteRemote host control

Logging

MethodDescription
SetLogger(string rootPath)Enable hourly-rotated session log files. Format: session_{date}_{hour}.log
WriteLog(string message)Write a custom entry prefixed with [Session][{userId}]

Events

OnSessionChanged

Fired when a user logs in, logs out, or is forcefully logged out.

Session.OnSessionChanged += (SessionEventArgs e) =>
{
// e.UserId, e.RoleLevel, e.ChangeType, e.Timestamp, e.ClientIp
Console.WriteLine($"{e.ChangeType}: {e.UserId} (role={e.RoleLevel})");
};
SessionChangeTypeDescription
LoginUser logged in
LogoutUser logged out normally
ForcedLogoutUser was forcefully logged out (e.g., by admin or timeout)

OnAuthenticationFailed

Fired when a login attempt fails.

Session.OnAuthenticationFailed += (AuthFailureEventArgs e) =>
{
// e.AttemptedUserId, e.FailureReason, e.FailureCount, e.ClientIp, e.Timestamp
Console.WriteLine($"Failed login: {e.AttemptedUserId}{e.FailureReason} (attempt {e.FailureCount})");
};

OnSessionTimeout

Fired when the current session times out due to inactivity.

Session.OnSessionTimeout += (TimeOutEventArgs e) =>
{
// e.UserId, e.LastActivityTime, e.InactivityDuration, e.Timestamp
Console.WriteLine($"Session expired: {e.UserId} after {e.InactivityDuration}");
};

Security Notes

  • Passwords are never stored in plaintext — bcrypt hashing is applied by the Rust FFI layer.
  • The singleton pattern ensures all [Auth] classes share one session state — a login from one component is visible to all.
  • Role-level enforcement for Control State transitions is performed on the Rust side, not in C#.

  • attribute — Port attribute reference ([Package], [Controller], etc.)
  • SECS/GEM — GEM Control State management (S1F17 Online/Offline)