OpenSimulator Internals/Code Map/ROBUST/LoginService
OpenSimulator Internals/Code Map/ROBUST/LoginService
[edit]Overview
[edit]LLLoginService handles viewer login requests. It is the most complex ROBUST service -- it orchestrates authentication, inventory, presence, destination selection, and agent launch across multiple other services.
Source file:
OpenSim/Services/LLLoginService/LLLoginService.cs
Constructor and Config Loading
[edit]LLLoginService(IConfigSource config, ISimulationService simService, ILibraryService libraryService)
[LoginService] section is required -- throws if absent.
Services loaded from [LoginService]:
| Key | Interface | Required |
|---|---|---|
| UserAccountService | IUserAccountService | Yes -- throws if empty |
| AuthenticationService | IAuthenticationService | Yes -- throws if empty |
| GridUserService | IGridUserService | No |
| UserAgentService | IUserAgentService | No |
| InventoryService | IInventoryService | No |
| GridService | IGridService | No |
| PresenceService | IPresenceService | No |
| AvatarService | IAvatarService | No |
| FriendsService | IFriendsService | No |
| SimulationService | ISimulationService | No -- remote connector |
| LibraryService | ILibraryService | No |
| HGInventoryServicePlugin | IInventoryService | No -- HG suitcase only |
AuthenticationService receives (config, IUserAccountService) as constructor args -- the only service that gets a second argument.
simService and libraryService may be passed directly as arguments (used by standalone mode); if null, the service loads them from config.
Additional config read:
| Section | Key | Default | Notes |
|---|---|---|---|
| [LoginService] | WelcomeMessage | "Welcome to OpenSim!" | Overridden by MessageUrl if fetch succeeds |
| [LoginService] | MessageUrl | (none) | URL to fetch welcome message from at startup |
| [LoginService] | RequireInventory | true | Fail login if inventory unavailable |
| [LoginService] | AllowRemoteSetLoginLevel | false | Allow SetLevel via HTTP |
| [LoginService] | MinLoginLevel | 0 | Minimum UserLevel to permit login |
| [LoginService] | GatekeeperURI | (none) | Also checked in [Startup] and [Hypergrid] |
| [LoginService] | MapTileURL | (none) | |
| [LoginService] | ProfileServerURL | (none) | |
| [LoginService] | OpenIDServerURL | (none) | |
| [LoginService] | SearchURL | (none) | |
| [LoginService] | Currency | (none) | |
| [LoginService] | ClassifiedFee | (none) | |
| [LoginService] | DestinationGuide | (none) | |
| [LoginService] | AvatarPicker | (none) | |
| [LoginService] | AllowLoginFallbackToAnyRegion | true | Legacy: try any online region if no default/fallback found |
| [LoginService] | DSTZone | "America/Los_Angeles;Pacific Standard Time" | |
| [AccessControl] or [LoginService] | AllowedClients | (none) | Regex matched against viewer string |
| [AccessControl] or [LoginService] | DeniedClients | (none) | Regex matched against viewer string |
| [AccessControl] or [LoginService] | DeniedMacs | (none) | Substring-matched against MAC |
| [AccessControl] or [LoginService] | DeniedID0s | (none) | Substring-matched against id0 |
| [Groups] | MaxAgentGroups | Constants.MaxAgentGroups | Max groups per avatar |
| [PresenceService] | AllowDuplicatePresences | false | If false, kick existing session on duplicate login |
| [Messaging] | MessageKey | (none) | Auth key for InstantMessage service |
WelcomeMessage priority: MessageUrl fetch (if configured and succeeds) overrides WelcomeMessage. If MessageUrl is configured but fetch fails, falls back to WelcomeMessage. "\n" in the message is replaced with a real newline.
SRV_ keys in [LoginService] override service URLs in AgentCircuitData and update the UserAccount record in the database if the value has changed.
Console commands registered once (static Initialized flag):
- login level <n> -- sets MinLoginLevel
- login reset -- resets MinLoginLevel to config value
- login text <text> -- sets welcome message
Login()
[edit]public LoginResponse Login(string firstName, string lastName, string passwd, string startLocation,
UUID scopeID, string clientVersion, string channel, string mac, string id0, IPEndPoint clientIP)
The main login path. Returns a LoginResponse (success) or LLFailedLoginResponse (failure). All failures are caught by a top-level try/catch that calls PresenceService.LogoutAgent() and returns LLFailedLoginResponse.InternalError.
Sequence:
- Client checks:
- If AllowedClientsRegex is set: clientVersion (or channel + " " + clientVersion) must match -- else LoginBlockedProblem
- If DeniedClientsRegex is set: must not match -- else LoginBlockedProblem
- If DeniedMacs is set: MAC must not appear as substring -- else LoginBlockedProblem
- If DeniedID0s is set: id0 must not appear as substring -- else LoginBlockedProblem
- Account lookup: GetUserAccount(scopeID, firstName, lastName) -- UserProblem if not found
- Level check: account.UserLevel < MinLoginLevel -- LoginBlockedProblem
- God account check: account.PrincipalID == Constants.servicesGodAgentID -- UserProblem (blocked)
- Scope check: if scopeID provided and account.ScopeID is nonzero and doesn't match -- UserProblem
- Authentication:
- Strips "$1$" prefix from passwd if present, otherwise MD5-hashes it
- Calls AuthenticationService.Authenticate() -- UserProblem if fails
- Duplicate presence check (if AllowDuplicatePresences = false):
- If GridUserInfo shows user is online with a known last region: sends god-kill IM to that region, calls LoggedOut(), returns AlreadyLoggedInProblem
- Inventory:
- If RequireInventory and InventoryService is null: InventoryProblem
- Calls HGInventoryService.GetRootFolder() if configured (creates suitcase folder)
- Calls InventoryService.GetInventorySkeleton() -- InventoryProblem if empty and RequireInventory
- Presence login: PresenceService.LoginAgent(principalID, session, secureSession) -- GridProblem if fails
- Home region lookup via GridService.GetRegionByUUID() using guinfo.HomeRegionID
- Destination selection: FindDestination() -- GridProblem if returns null; also logs out presence
- Avatar appearance: AvatarService.GetAppearance() if configured
- Agent launch: LaunchAgentAtGrid() -- logs out presence and returns failure reason if null
- GridUserService.LoggedIn() -- called only after successful agent launch
- Friends list: FriendsService.GetFriends()
- Active gestures: InventoryService.GetActiveGestures()
- Builds and returns LLLoginResponse
FindDestination()
[edit]protected GridRegion FindDestination(...)
Resolves startLocation to a GridRegion. Returns null if no region can be found. Sets out parameters: gatekeeper, where ("home"/"last"/"url"/"safe"), position, lookAt, flags.
startLocation values:
"home":
- Uses guinfo.HomeRegionID -- returns home region if found
- Falls back to GridService.GetDefaultRegions()[0] (where = "safe")
- Falls back to FindAlternativeRegion() (where = "safe")
- Returns null if nothing found
"last":
- Uses guinfo.LastRegionID -- returns last region if found, clamps position within region bounds
- Falls back to default regions, then FindAlternativeRegion()
URI form (uri:RegionName&x&y&z):
- Parsed by compiled Regex: ^uri:(?<region>[^&]+)&(?<x>\d+[.]?\d*)&(?<y>\d+[.]?\d*)&(?<z>\d+[.]?\d*)$
- If region name contains '@': direct HG login -- explicitly rejected ("no longer supported"), returns null. The original implementation is present but commented out.
- Otherwise: GridService.GetRegionByName(), falls back to defaults, then FindAlternativeRegion()
FindAlternativeRegion():
- Tries GetFallbackRegions() near coordinate 1000,1000
- If AllowLoginFallbackToAnyRegion: tries GetOnlineRegions() near 1000,1000 (up to 10)
- Returns null if nothing found
LaunchAgentAtGrid()
[edit]protected AgentCircuitData LaunchAgentAtGrid(...)
Builds AgentCircuitData via MakeAgent() and launches the agent at the destination region.
Two paths depending on whether UserAgentService is configured:
Without UserAgentService (non-HG or standalone):
- Uses LocalSimulationService if available, else RemoteSimulationService
- Calls LaunchAgentDirectly(): QueryAccess() then CreateAgent()
- On failure: tries fallback regions from GridService.GetFallbackRegions()
With UserAgentService (HG-enabled):
- Constructs gatekeeper GridRegion from m_GatekeeperURL if not already provided
- Calls LaunchAgentIndirectly(): UserAgentService.LoginAgentToGrid()
- On failure: tries fallback regions
Returns AgentCircuitData on success, null on failure.
MakeAgent() populates AgentCircuitData:
- Generates random circuit code
- Sets appearance (or empty AvatarAppearance if none)
- Generates random CapsPath
- Sets child = false (login agent is always root)
- Calls SetServiceURLs()
SetServiceURLs():
- Copies ServiceURLs from UserAccount record
- Overrides with SRV_-prefixed keys from [LoginService] config
- Appends GatekeeperURI if configured
- Calls UserAccountService.StoreUserAccount() if any URLs were updated
SetLevel()
[edit]public Hashtable SetLevel(string firstName, string lastName, string passwd, int level, IPEndPoint clientIP)
Remote login level control. Only active if AllowRemoteSetLoginLevel = true. Requires the caller to authenticate as a user with UserLevel >= 200. Sets m_MinLoginLevel to the requested level. Returns Hashtable with success = "false" on any failure, success = true on success.
SendAgentGodKillToRegion()
[edit]Called during duplicate presence handling. Sends a god-kick InstantMessage (dialog = 250) from Constants.servicesGodAgentID to the agent's last known region via InstantMessageServiceConnector.SendInstantMessage(). Calls GridUserService.LoggedOut() after sending. Returns false if the region cannot be found or has no ServerURI.
Notes
[edit]- Direct HG login via URI (region@host:port form) is explicitly disabled. The original implementation is present as a large commented-out block with the note that it no longer works due to teleport flag changes and suitcase issues.
- The god account (Constants.servicesGodAgentID) is explicitly blocked from logging in.
- GridUserService.LoggedIn() is called only after LaunchAgentAtGrid() succeeds -- if agent launch fails, the GridUser record is not updated.
- PresenceService.LoginAgent() is called before destination is confirmed. If FindDestination() or LaunchAgentAtGrid() fails, LogoutAgent() is called to clean up.
- AllowedClients and DeniedClients regex compilation failures are caught and logged; the regex is set to null, meaning the check is skipped rather than blocking all logins.