# IAM Service .NET 10

> **Service IAM (Identity and Access Management) .NET 10 với OAuth2/OIDC sử dụng Duende IdentityServer.**

## Tổng Quan

IAM Service cung cấp các chức năng quản lý danh tính và truy cập:

- **OAuth2/OIDC** - Authentication với Duende IdentityServer
- **User Management** - CRUD operations cho users
- **Password Management** - Đổi mật khẩu
- **Token Management** - Issue, refresh, revoke tokens
- **Email Verification** - Xác thực email qua SMTP
- **2FA/MFA** - Xác thực hai yếu tố với TOTP
- **Social Login** - Đăng nhập qua Google và Facebook
- **CQRS Pattern** - MediatR cho Commands/Queries
- **Clean Architecture** - Domain, Infrastructure, API layers

## Yêu Cầu

| Yêu cầu | Phiên bản |
|---------|-----------|
| .NET SDK | 10.0.101+ |
| Docker | 24.0+ |
| PostgreSQL | 15+ |

## Bắt Đầu Nhanh

### Chạy với Docker

```bash
cd deployments/local
docker-compose up -d
```

### Chạy Local

```bash
cd services/iam-service-net
dotnet restore
dotnet build
dotnet run --project src/IamService.API
```

## Database Migrations

### Yêu Cầu

```bash
# Cài đặt EF Core tools (một lần)
dotnet tool install --global dotnet-ef
```

### Tạo Migration

```bash
# Tạo migration mới
dotnet ef migrations add <TenMigration> \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API
```

### Áp Dụng Migration

```bash
# Áp dụng migrations vào database
dotnet ef database update \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API
```

### Các Lệnh Khác

```bash
# Xóa migration cuối (nếu chưa áp dụng)
dotnet ef migrations remove \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API

# Tạo SQL script
dotnet ef migrations script \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API \
  --output migrations.sql

# Liệt kê migrations
dotnet ef migrations list \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API
```

### Thiết Lập Neon Database

1. Tạo database trên [Neon Console](https://console.neon.tech)
2. Sao chép connection string
3. Cập nhật `appsettings.Development.json`:
```json
{
  "ConnectionStrings": {
    "DefaultConnection": "Host=<host>;Port=5432;Database=<db>;Username=<user>;Password=<pass>;SSL Mode=Require"
  }
}
```
4. Chạy migrations: `dotnet ef database update ...`

## API Endpoints

### Authorization Policies (Phân Quyền API)

> **Lưu ý:** Tất cả API endpoints yêu cầu xác thực (Bearer JWT Token).  
> Một số endpoints yêu cầu role cụ thể như bảng dưới đây.

| Policy | Required Role | Áp Dụng Cho |
|--------|---------------|-------------|
| `RequireSuperAdmin` | SuperAdmin | PAM (Privileged Access Management) |
| `RequireAdmin` | Admin, SuperAdmin | User/Role/Group/Organization management |
| `RequireAuditor` | Auditor, Admin, SuperAdmin | Audit logs, Compliance reports |
| `OwnerOrAdmin` | Owner hoặc Admin | User tự quản lý profile của mình |

**Chi tiết phân quyền theo Controller:**

| Controller | Policy | Mô tả |
|------------|--------|-------|
| Users (GET /users, DELETE) | RequireAdmin | Xem danh sách users, xóa user |
| Users (GET/PUT /{id}) | OwnerOrAdmin | User xem/sửa profile mình hoặc Admin |
| Roles | RequireAdmin | Quản lý roles |
| Organizations | RequireAdmin | Quản lý tổ chức |
| Groups | RequireAdmin | Quản lý nhóm |
| Access Requests | RequireAdmin | Xử lý yêu cầu truy cập |
| Access Reviews | RequireAdmin | Xem xét truy cập định kỳ |
| Privileged Access | RequireSuperAdmin | PAM - nhạy cảm nhất |
| Audit | RequireAuditor | Xem audit logs |
| Compliance | RequireAuditor | Báo cáo tuân thủ |
| Verifications | RequireAdmin | Xác thực danh tính |

### Authentication (`/api/v1/auth`)

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `POST` | `/api/v1/auth/register` | Đăng ký user mới | ❌ |
| `POST` | `/connect/token` | OAuth2 Token (login, refresh) | ❌ |
| `POST` | `/api/v1/auth/change-password` | Đổi mật khẩu | ✅ |
| `POST` | `/api/v1/auth/logout` | Đăng xuất (revoke tokens) | ✅ |

### Email Verification (`/api/v1/auth`)

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `POST` | `/api/v1/auth/send-verification-email` | Gửi email xác thực | ✅ |
| `POST` | `/api/v1/auth/confirm-email` | Xác nhận email với token | ❌ |

### Xác Thực Hai Yếu Tố (`/api/v1/auth/2fa`)

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `POST` | `/api/v1/auth/2fa/enable` | Bật 2FA (lấy QR code) | ✅ |
| `POST` | `/api/v1/auth/2fa/verify` | Xác minh mã TOTP & kích hoạt | ✅ |
| `POST` | `/api/v1/auth/2fa/disable` | Tắt 2FA | ✅ |

### Đăng Nhập Mạng Xã Hội (`/api/v1/auth`)

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `GET` | `/api/v1/auth/external-login/{provider}` | Bắt đầu OAuth flow (Google/Facebook) | ❌ |
| `GET` | `/api/v1/auth/external-callback` | Xử lý OAuth callback | ❌ |
| `GET` | `/api/v1/auth/linked-accounts` | Lấy danh sách providers đã liên kết | ✅ |

### User Management (`/api/v1/users`)

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `GET` | `/api/v1/users` | Lấy danh sách users (phân trang) | ✅ |
| `GET` | `/api/v1/users/me` | Lấy thông tin user hiện tại | ✅ |
| `GET` | `/api/v1/users/{id}` | Lấy user theo ID | ✅ |
| `PUT` | `/api/v1/users/{id}` | Cập nhật thông tin user | ✅ |
| `DELETE` | `/api/v1/users/{id}` | Xóa user (soft delete) | ✅ |
| `GET` | `/api/v1/users/{id}/roles` | Lấy danh sách roles của user | ✅ |
| `GET` | `/api/v1/users/{id}/permissions` | Lấy danh sách permissions của user | ✅ |

### Profile Người Dùng (`/api/v1/users/{userId}/profile`)

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `GET` | `/api/v1/users/{userId}/profile` | Lấy profile user | ✅ |
| `PUT` | `/api/v1/users/{userId}/profile` | Cập nhật profile user | ✅ |
| `PUT` | `/api/v1/users/{userId}/profile/attributes/{key}` | Đặt attribute profile | ✅ |

### Quản Lý Roles (`/api/v1/roles`)

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `GET` | `/api/v1/roles` | Danh sách roles (phân trang) | ✅ |
| `GET` | `/api/v1/roles/{id}` | Lấy role theo ID | ✅ |
| `POST` | `/api/v1/roles` | Tạo role mới | ✅ |
| `PUT` | `/api/v1/roles/{id}` | Cập nhật role | ✅ |
| `DELETE` | `/api/v1/roles/{id}` | Xóa role | ✅ |
| `POST` | `/api/v1/roles/users/{userId}` | Gán role cho user | ✅ |
| `DELETE` | `/api/v1/roles/users/{userId}/{roleName}` | Xóa role khỏi user | ✅ |

### Xác Thực Danh Tính (`/api/v1/verifications`)

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `POST` | `/api/v1/verifications/phone` | Yêu cầu xác thực số điện thoại | ✅ |
| `POST` | `/api/v1/verifications/email` | Yêu cầu xác thực email | ✅ |
| `POST` | `/api/v1/verifications/{id}/confirm` | Xác nhận với mã xác thực | ✅ |

### Health Checks

| Endpoint | Mục Đích |
|----------|----------|
| `/health` | Trạng thái health đầy đủ |
| `/health/live` | Kiểm tra sống |
| `/health/ready` | Kiểm tra sẵn sàng |

### Organizations (`/api/v1/organizations`) - Phase 2

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `GET` | `/api/v1/organizations/{id}` | Lấy tổ chức theo ID | ✅ |
| `GET` | `/api/v1/organizations/slug/{slug}` | Lấy tổ chức theo slug | ✅ |
| `POST` | `/api/v1/organizations` | Tạo tổ chức mới | ✅ |
| `PUT` | `/api/v1/organizations/{id}` | Cập nhật tổ chức | ✅ |
| `DELETE` | `/api/v1/organizations/{id}` | Lưu trữ tổ chức | ✅ |
| `GET` | `/api/v1/organizations/{id}/hierarchy` | Lấy phân cấp | ✅ |
| `GET` | `/api/v1/organizations/{id}/children` | Lấy tổ chức con | ✅ |

### Groups (`/api/v1/groups`) - Phase 2

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `GET` | `/api/v1/groups` | Danh sách groups | ✅ |
| `GET` | `/api/v1/groups/{id}` | Lấy group theo ID | ✅ |
| `POST` | `/api/v1/groups` | Tạo group mới | ✅ |
| `DELETE` | `/api/v1/groups/{id}` | Xóa group | ✅ |
| `POST` | `/api/v1/groups/{id}/members` | Thêm thành viên | ✅ |
| `DELETE` | `/api/v1/groups/{id}/members/{userId}` | Xóa thành viên | ✅ |

### Access Requests (`/api/v1/access-requests`) - Phase 3A

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `POST` | `/api/v1/access-requests` | Tạo yêu cầu truy cập | ✅ |
| `GET` | `/api/v1/access-requests` | Danh sách requests | ✅ |
| `GET` | `/api/v1/access-requests/{id}` | Lấy request theo ID | ✅ |
| `POST` | `/api/v1/access-requests/{id}/submit` | Submit request | ✅ |
| `POST` | `/api/v1/access-requests/{id}/approve` | Phê duyệt | ✅ |
| `POST` | `/api/v1/access-requests/{id}/reject` | Từ chối | ✅ |
| `DELETE` | `/api/v1/access-requests/{id}` | Hủy request | ✅ |
| `GET` | `/api/v1/access-requests/pending` | Requests đang chờ | ✅ |

### Access Reviews (`/api/v1/access-reviews`) - Phase 3B

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `POST` | `/api/v1/access-reviews` | Tạo access review | ✅ |
| `GET` | `/api/v1/access-reviews/{id}` | Lấy review theo ID | ✅ |
| `POST` | `/api/v1/access-reviews/{id}/items` | Thêm item | ✅ |
| `POST` | `/api/v1/access-reviews/{id}/start` | Bắt đầu review | ✅ |
| `POST` | `/api/v1/access-reviews/{id}/items/{itemId}/review` | Certify/Revoke | ✅ |
| `POST` | `/api/v1/access-reviews/{id}/complete` | Hoàn thành | ✅ |

### Privileged Access (`/api/v1/privileged-access`) - Phase 3B PAM

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `POST` | `/api/v1/privileged-access/request` | Yêu cầu JIT access | ✅ |
| `GET` | `/api/v1/privileged-access/active` | Grants đang active | ✅ |
| `POST` | `/api/v1/privileged-access/{id}/revoke` | Thu hồi access | ✅ |

### Audit (`/api/v1/audit`) - Phase 4A

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `GET` | `/api/v1/audit/logs` | Lấy audit logs (filtered) | ✅ |

### Compliance (`/api/v1/compliance`) - Phase 4A

| Method | Endpoint | Mô Tả | Auth |
|--------|----------|-------|------|
| `POST` | `/api/v1/compliance/reports` | Generate report | ✅ |
| `GET` | `/api/v1/compliance/reports` | Danh sách reports | ✅ |
| `GET` | `/api/v1/compliance/reports/{id}` | Report chi tiết | ✅ |
| `POST` | `/api/v1/compliance/reports/{id}/complete` | Hoàn thành report | ✅ |
| `GET` | `/api/v1/compliance/violations` | Violations chưa giải quyết | ✅ |

## Quy Trình Xác Thực

### Bước 1: Đăng Ký User Mới

```bash
curl -X POST http://localhost:5001/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "Password123!",
    "firstName": "John",
    "lastName": "Doe"
  }'
```

**Response:**
```json
{
  "success": true,
  "data": {
    "userId": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com"
  }
}
```

### Bước 2: Đăng Nhập (Password Grant)

```bash
curl -X POST http://localhost:5001/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password" \
  -d "client_id=password-client" \
  -d "client_secret=password-client-secret" \
  -d "username=user@example.com" \
  -d "password=Password123!" \
  -d "scope=openid profile email api offline_access"
```

**Response:**
```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9...",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9...",
  "scope": "openid profile email offline_access"
}
```

### Bước 3: Sử Dụng Access Token

Sử dụng `access_token` trong header `Authorization` cho các API được bảo vệ:

```bash
curl http://localhost:5001/api/v1/users/me \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9..."
```

### Bước 4: Làm Mới Token (Khi Access Token Hết Hạn)

```bash
curl -X POST http://localhost:5001/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9..."
```

### Bước 5: Đăng Xuất

```bash
curl -X POST http://localhost:5001/api/v1/auth/logout \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

### Client Credentials (Service-to-Service)

```bash
curl -X POST http://localhost:5001/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=goodgo-service" \
  -d "client_secret=service-secret" \
  -d "scope=api"
```

## Xác Thực Email

### Gửi Email Xác Thực

```bash
curl -X POST http://localhost:5001/api/v1/auth/send-verification-email \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'
```

### Xác Nhận Email

```bash
curl -X POST http://localhost:5001/api/v1/auth/confirm-email \
  -H "Content-Type: application/json" \
  -d '{"userId": "user-guid", "token": "confirmation-token"}'
```

## Xác Thực Hai Yếu Tố (2FA)

### Bật 2FA

```bash
curl -X POST http://localhost:5001/api/v1/auth/2fa/enable \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

**Response:**
```json
{
  "success": true,
  "data": {
    "secretKey": "JBSWY3DPEHPK3PXP",
    "qrCodeBase64": "data:image/png;base64,...",
    "recoveryCodes": ["code1", "code2", "code3", ...]
  }
}
```

### Xác Minh Mã 2FA

```bash
curl -X POST http://localhost:5001/api/v1/auth/2fa/verify \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"code": "123456"}'
```

### Tắt 2FA

```bash
curl -X POST http://localhost:5001/api/v1/auth/2fa/disable \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"code": "123456"}'
```

## Đăng Nhập Mạng Xã Hội

### Bắt Đầu OAuth Flow

Chuyển hướng user tới:
```
GET http://localhost:5001/api/v1/auth/external-login/Google?returnUrl=http://your-app/callback
GET http://localhost:5001/api/v1/auth/external-login/Facebook?returnUrl=http://your-app/callback
```

### Lấy Tài Khoản Đã Liên Kết

```bash
curl http://localhost:5001/api/v1/auth/linked-accounts \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

**Response:**
```json
{
  "success": true,
  "data": {
    "linkedProviders": [
      {"provider": "Google", "providerDisplayName": "Google"},
      {"provider": "Facebook", "providerDisplayName": "Facebook"}
    ]
  }
}
```

## Swagger UI

Sau khi chạy service, truy cập Swagger UI tại:
- **Local**: http://localhost:5001/swagger
- **Docker**: http://localhost/api/v1/iam/swagger

## Cấu Hình

### Biến Môi Trường

| Biến | Mô Tả | Mặc định |
|------|-------|----------|
| `ASPNETCORE_ENVIRONMENT` | Môi trường | `Development` |
| `DATABASE_URL` | PostgreSQL connection | - |
| `JWT_SECRET` | Secret ký JWT (32+ ký tự) | - |
| `REDIS_HOST` | Redis server host | `localhost` |
| `REDIS_PORT` | Redis server port | `6379` |
| `REDIS_PASSWORD` | Redis password | - |
| `REDIS_DATABASE` | Redis database number | `0` |

## Redis Caching

Service sử dụng Redis cho distributed caching thông qua interface `ICacheService`.

### Cấu Hình Redis

Thêm cấu hình Redis trong `appsettings.json`:

```json
{
  "Redis": {
    "Host": "localhost",
    "Port": 6379,
    "Password": "",
    "Database": 0,
    "ConnectTimeout": 5000,
    "SyncTimeout": 5000
  }
}
```

Hoặc sử dụng biến môi trường:

```bash
REDIS_HOST=your-redis-host
REDIS_PORT=6379
REDIS_PASSWORD=your-password
REDIS_DATABASE=0
```

### ICacheService Interface

```csharp
public interface ICacheService
{
    // Các thao tác cơ bản
    Task<T?> GetAsync<T>(string key);
    Task SetAsync<T>(string key, T value, TimeSpan? expiration = null);
    Task RemoveAsync(string key);
    Task<bool> ExistsAsync(string key);
    
    // Get hoặc tạo mới pattern
    Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null);
    
    // Hỗ trợ blacklist token
    Task BlacklistAsync(string key, TimeSpan expiration);
    Task<bool> IsBlacklistedAsync(string key);
}
```

### Ví Dụ Sử Dụng

**Get/Set cơ bản:**
```csharp
public class MyService
{
    private readonly ICacheService _cache;
    
    public MyService(ICacheService cache) => _cache = cache;
    
    public async Task<User?> GetUser(string userId)
    {
        return await _cache.GetAsync<User>($"user:{userId}");
    }
    
    public async Task CacheUser(User user)
    {
        await _cache.SetAsync($"user:{user.Id}", user, TimeSpan.FromMinutes(15));
    }
}
```

**Get or Set Pattern (Cache-Aside):**
```csharp
public async Task<User> GetUserById(string userId)
{
    return await _cache.GetOrSetAsync(
        $"user:{userId}",
        async () => await _repository.GetByIdAsync(userId),
        TimeSpan.FromMinutes(15)
    );
}
```

**Blacklist Token (cho Logout):**
```csharp
public async Task Logout(string tokenId)
{
    // Blacklist refresh token trong thời gian còn lại của token
    await _cache.BlacklistAsync($"token:{tokenId}", TimeSpan.FromDays(7));
}

public async Task<bool> IsTokenRevoked(string tokenId)
{
    return await _cache.IsBlacklistedAsync($"token:{tokenId}");
}
```

## Kiểm Thử

```bash
dotnet test
```

## Triển Khai

### Docker Build

```bash
docker build -t goodgo/iam-service:latest .
docker run -p 5001:8080 --env-file .env goodgo/iam-service:latest
```

## Tài Nguyên

- [Duende IdentityServer Documentation](https://docs.duendesoftware.com/identityserver/v7/)
- [ASP.NET Core Identity](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity)
- [OAuth2 Specification](https://oauth.net/2/)
