# adas-core.LocalLogin — Local Authentication Strategy

> An **authentication strategy** project of the ADAS Core platform.  
> Implements the `ILoginService` contract from `adas-core.Authentication` for credential validation against locally stored users. This is a **concrete strategy** in the Strategy Pattern, interchangeable with `adas-core.LdapLogin` at runtime.

---

## Table of Contents

1. [Overview](#overview)
2. [Responsibilities](#responsibilities)
3. [Project Structure](#project-structure)
4. [Dependencies](#dependencies)
5. [Local Authentication Flow](#local-authentication-flow)
6. [User Management](#user-management)
7. [Design Rules](#design-rules)

---

## Overview

`adas-core.LocalLogin` is one of the interchangeable authentication strategies in the ADAS Core platform. It implements `ILoginService` using locally persisted `User` records as the credential source. Credentials are verified against hashed passwords stored in the application database (typically MongoDB via the `LocalLoginRepository`).

Key characteristics:

- **Strategy Conformance** — Implements `ILoginService` so the Host can switch authentication schemes without code changes.
- **Local Credential Store** — Validates username/password against users persisted in the application's primary data store.
- **Password Verification** — Delegates password hashing verification to `CryptoAdas` (a domain-level cryptographic utility), keeping hashing logic out of this project.
- **Full CRUD Support** — Unlike `LdapLogin`, this strategy supports user lookup, listing, and soft-authentication (`Authenticate`) in addition to login.
- **Self-Contained** — All local-authentication-specific dependencies live here; the `Authentication` layer remains strategy-agnostic.

---

## Responsibilities

| Concern | What this project does |
|---------|----------------------|
| **Credential Validation** | Retrieves the local `User` record by username and verifies the password hash using `CryptoAdas.VerifyPassword`. |
| **User Lookup** | Provides `GetById`, `GetByEmail`, `GetByUsername`, and `GetAllUsers` for user management operations. |
| **Soft Authentication** | `Authenticate()` returns a user object (or empty) without throwing exceptions, useful for middleware or conditional flows. |
| **Authority Resolution** | Loads the user's `Authorization` collection from `IAuthorityService` upon successful login. |
| **Repository Implementation** | `LocalLoginRepository` implements `ILocalLoginRepository`, extending `MongoRepository<User>` with user-specific queries. |
| **System User Seeding** | Ensures a "System" user exists in the database on startup via `InsertInitialLoad`. |
| **DI Registration** | `LocalLoginExtension.AddLocalLogin()` wires the repository, service, and authority contracts into the Host container. |

---

## Project Structure

```
adas-core.LocalLogin/
├── LocalLoginServiceImpl.cs       # Core ILoginService implementation
├── ILocalLoginRepository.cs        # Repository contract extending IMongoRepository<User>
├── LocalLoginRepository.cs         # Concrete MongoDB-backed user repository
│
└── RegistrationExtension/
    └── LocalLoginExtension.cs      # Host extension: AddLocalLogin()
```

| File | Role |
|------|------|
| `LocalLoginServiceImpl.cs` | Implements `ILoginService.Login()`, `Authenticate()`, and user lookup methods. Delegates persistence to `ILocalLoginRepository`. |
| `ILocalLoginRepository.cs` | Defines user-specific queries: `GetByUsername`, `GetByEmail`, `GetById`, `GetAll`, `InsertUserOneAsync`, `UpdateOneUserAsync`. |
| `LocalLoginRepository.cs` | Concrete repository extending `MongoRepository<User>`. Implements queries with MongoDB filters and seeds a system user on startup. |
| `LocalLoginExtension.cs` | Registers `ILocalLoginRepository`, `ILoginService`, `IAuthorityService`, and `IAuthorityRepository` as singletons in DI. |

---

## Dependencies

### Downstream References

| Project | Role |
|---------|------|
| `adas-core.Authentication` | Defines `ILoginService`, `IAuthorityService`, and `IUserService` contracts implemented by this strategy. |
| `adas-core.Domain` | Provides `User`, `UserEnum.LoginMethod`, `UnauthorizedException`, `LoginServicesException`, `HttpEnum`, and `CryptoAdas`. |
| `adas-core.Infrastructure` | Inherits `MongoRepository<User>` and uses `IMongoDatabase` for persistence. |

### Upstream References (projects that depend on this)

| Project | Reason |
|---------|--------|
| `adas-core` (Host) | Calls `AddLocalLogin()` during startup when `Authentication:Scheme` is `"Local"`. Routes login requests to this implementation. |

### NuGet Packages

| Package | Version | Purpose |
|---------|---------|---------|
| `Portable.BouncyCastle` | 1.9.0 | Cryptographic primitives available for potential custom hash extensions (primary hashing is via `CryptoAdas` in Domain). |
| `AuditLogs` | 1.0.59 | Audit logging of login attempts and user CRUD operations. |

---


## Local Authentication Flow

```
┌─────────────────┐     ┌────────────────────┐     ┌─────────────────┐
│  User enters    │────▶│ LocalLoginServiceImpl│────▶│ GetByUsername   │
│  credentials    │     │ .Login(uname, pwd) │     │ (ILocalLoginRepo)│
└─────────────────┘     └────────────────────┘     └─────────────────┘
                                                             │
                                                             ▼
                                                    ┌─────────────────┐
                                                    │  VerifyPassword   │
                                                    │  (CryptoAdas)     │
                                                    └─────────────────┘
                                                             │
                                      ┌──────────────────────┼──────────────────────┐
                                      │                      │                      │
                                      ▼                      ▼                      ▼
                              ┌──────────────┐      ┌──────────────┐      ┌──────────────┐
                              │  Success     │      │  Not Found   │      │  Bad Password│
                              │  Load Roles  │      │  Unauthorized│      │  Unauthorized│
                              └──────────────┘      └──────────────┘      └──────────────┘
```

### Detailed Steps

1. **Lookup** — `LocalLoginServiceImpl` calls `ILocalLoginRepository.GetByUsername(username)`.
2. **Existence Check** — If no user is found, throws `UnauthorizedException` with `UnauthorizedInvalidCredentials`.
3. **Password Verification** — Calls `CryptoAdas.VerifyPassword(password, userFound.Password)` using the stored bcrypt hash.
4. **Validation Failure** — If verification fails, throws `UnauthorizedException`.
5. **Authority Load** — Retrieves the user's `Authorization` collection via `IAuthorityService.GetUserAuthorities(userFound.Id)`.
6. **Return** — Returns the fully populated `User` entity with roles.

---

## User Management

### Implemented ILoginService Methods

| Method | Behavior |
|--------|----------|
| `Login(username, password)` | Validates credentials strictly; throws `UnauthorizedException` on failure. |
| `Authenticate(username, password)` | Soft validation; returns user on success, empty `User` on failure (no exceptions). |
| `GetById(id)` | Retrieves user by `ObjectId`. |
| `GetByEmail(email)` | Retrieves user by email address. |
| `GetByUsername(username)` | Retrieves user by username. |
| `GetAllUsers()` | Lists all users in the local repository. |
| `Login(HttpContext)` | Throws `LoginServicesException("Not implemented")` — no token-based or HTTP-context login for local strategy. |

### LocalLoginRepository Features

- **Collection Override** — Overrides `GetCollectionName()` to use the collection name from `ApiSettings`.
- **System User Seeding** — `InsertInitialLoad()` ensures a `UserName = "System"` account exists with a pre-hashed password.
- **CRUD Operations** — `InsertUserOneAsync`, `UpdateOneUserAsync`, `GetById`, `GetByEmail`, `GetByUsername`, `GetAll`.

---

## Design Rules

1. **Strategy Contract Compliance** — Must implement `ILoginService` exactly. No additional public surface beyond the interface.
2. **No Business Logic** — Orchestrates credential lookup and verification. Business rules (lockout policy, password complexity) belong in `Authentication` or `Application`.
3. **Password Hashing Delegation** — Never implements custom password hashing. Delegates to `CryptoAdas` from `adas-core.Domain` to ensure consistency across strategies.
4. **Repository Abstraction** — `LocalLoginServiceImpl` depends only on `ILocalLoginRepository`, never on `MongoRepository` directly. This enables test doubles.
5. **Exception Translation** — Invalid credentials always raise `UnauthorizedException`. Infrastructure errors (MongoDB connection failures) are logged and re-thrown as domain exceptions.
6. **Idempotent Seeding** — `InsertInitialLoad` checks for the system user before inserting. Safe to call multiple times.
7. **Audit Trail** — Every login attempt (success and failure) and every user mutation emits an audit event via `AuditLogs`.
8. **Singleton Lifetime** — `LocalLoginServiceImpl`, `LocalLoginRepository`, and `AuthorityService` are registered as **Singletons** because they are stateless and thread-safe.
9. **Open/Closed Principle** — Adding a new authentication strategy (OAuth, SAML) must not require modifying this project. It is a standalone plugin.
10. **No Hardcoded Values** — Collection names come from `ApiSettings`. System user credentials are injected or configured, never magic strings in code.

---

<p align="center">
  Back to <a href="../README.md">adas-core Root README</a>
</p>

