diff --git a/internal/cognitoauth/auth.go b/internal/cognitoauth/auth.go index c675e868..bfb1fd4d 100644 --- a/internal/cognitoauth/auth.go +++ b/internal/cognitoauth/auth.go @@ -47,17 +47,6 @@ func RegisterRoutes(e *echo.Echo, config auth.ConfigProvider) { }) }) - //fmt.Printf("registering logoutpath: %s \v", config.GetAuthLogoutPath()) - //// Register logout route - //e.GET(config.GetAuthLogoutPath(), func(c echo.Context) error { - // return LogoutHandler(c) - //}) - - //// Default home page handler if requested - //e.GET(config.GetAuthHomePath(), func(c echo.Context) error { - // return HomeHandler(c, config) - //}) - // Apply the JWT Auth middleware first e.Use(JWTAuthMiddleware(config)) @@ -65,183 +54,6 @@ func RegisterRoutes(e *echo.Echo, config auth.ConfigProvider) { e.Use(TokenValidationMiddleware(config)) } -// HomeHandler implements a simple home page that shows auth status and available endpoints -func HomeHandler(c echo.Context, config auth.ConfigProvider) error { - // Create a list of all registered routes - println("HomeHandler called.") - - var endpoints []string - - // Add the auth routes - endpoints = append(endpoints, []string{ - config.GetAuthLoginPath(), - config.GetAuthCallbackPath(), - config.GetAuthHomePath(), - config.GetAuthLogoutPath(), - }...) - - // Add routes from the permission map - for route := range config.GetAuthRoutePermissions() { - // Skip routes that are already in the list - alreadyAdded := false - for _, endpoint := range endpoints { - if route == endpoint { - alreadyAdded = true - break - } - } - if !alreadyAdded { - endpoints = append(endpoints, route) - } - } - - // Check if user is authenticated by looking for token in cookie - tokenCookie, err := c.Cookie("auth_token") - isAuthenticated := (err == nil && tokenCookie.Value != "") - - // Variables for user info - username := "" - email := "" - var userGroups []string - - // If authenticated, try to decode the JWT token to get user info - if isAuthenticated { - // Parse the JWT token without verification (just to extract info for display) - token, _ := jwt.Parse([]byte(tokenCookie.Value), jwt.WithVerify(false)) - if token != nil { - claims, _ := token.AsMap(context.Background()) - username, _ = claims["cognito:username"].(string) - email, _ = claims["email"].(string) - - // Try to extract groups - userGroups, _ = GetUserGroups(claims) - } - } - - // Create HTML for the endpoints list - var linksHTML string - baseURL := c.Scheme() + "://" + c.Request().Host - - // Create list items for each endpoint - for _, endpoint := range endpoints { - // Skip endpoints with path parameters for direct linking - if strings.Contains(endpoint, ":") { - displayPath := strings.Replace(endpoint, ":id", "{id}", -1) - linksHTML += fmt.Sprintf("
  • %s (requires parameter)
  • \n", displayPath) - } else { - linksHTML += fmt.Sprintf("
  • %s
  • \n", baseURL, endpoint, endpoint) - } - } - - // Create authentication status section - var authStatusHTML string - if isAuthenticated { - authStatusHTML = fmt.Sprintf(` -
    -

    Authentication Status: Authenticated

    -

    Username: %s

    -

    Email: %s

    -

    Groups: %s

    -

    Logout

    -
    - `, username, email, strings.Join(userGroups, ", "), baseURL) - } else { - authStatusHTML = fmt.Sprintf(` -
    -

    Authentication Status: Not Authenticated

    -

    You are not currently logged in.

    -

    -
    - `, baseURL) - } - - // Create the complete HTML page - html := fmt.Sprintf(` - - - - Authentication Home - - - -

    Authentication Home

    - - %s - -

    Available Endpoints

    - - -
    -

    Note: This is a debugging page. Some endpoints require authentication or specific permissions.

    -
    - - - `, authStatusHTML, linksHTML) - - return c.HTML(http.StatusOK, html) -} - // GetTokenFromRequest extracts the token from the request func GetTokenFromRequest(c echo.Context) string { // First try from Authorization header diff --git a/internal/cognitoauth/readme.md b/internal/cognitoauth/readme.md index 4ad8f29f..85bb9ab5 100644 --- a/internal/cognitoauth/readme.md +++ b/internal/cognitoauth/readme.md @@ -31,3 +31,7 @@ The package reads configuration from environment variables: - `AWS_REGION`: AWS region where your Cognito User Pool is located (us-east-2) - `DEBUG`: Set to "true" for debug logging +## Route Permissions +Route permissions are hard-coded in the `route_permissions.go` file. +In the future we may +integrate this information into the swagger API document. \ No newline at end of file diff --git a/internal/cognitoauth/summary.md b/internal/cognitoauth/summary.md index ae260adf..1a0e228a 100644 --- a/internal/cognitoauth/summary.md +++ b/internal/cognitoauth/summary.md @@ -37,6 +37,9 @@ This package uses AWS Cognito for authentication and implements Role-Based Acces - **Registers Cognito RBAC middleware and routes before registering API handlers.** - Sets route-level permissions via a map of route to allowed groups. +## Cognito client user group setup +The cognito client must be setup to redirect back to /login-callback for PKCE flow to work. + ## Integration Flow 1. **Config Initialization**: Auth config and route permissions are loaded at startup. @@ -79,3 +82,30 @@ RegisterHandlers(echoRouter, controllers) - Route permissions are fully customizable. - Middleware can be extended or replaced for fine-grained control. - User info is accessible in handlers via helper functions. + + +## Cognito auth flow (mermaid) +For a live graph of the auto flow go [here.](https://mermaid.live/edit#pako:eNp9VE2P2jAQ_SsjH3pisyQQAlHLimVXvfQDle0eKqTK6wxgAXZqO7sFxH_vOISvhZKDFdvPb968GXvNhM6QpczinwKVwAfJJ4YvRgroy7lxUsicKwf3Rr9ZNOcbvTwfonlFA9zCgxarZS-X94_nwL6eKOn0dmM7VqQ33e6eJYUwgM-PT3A71xOptrhv2iFoH-MIFxEOFRpOez6L37QqxxLNxxdz2z3dElM-n6Oa4JZvz0KRKw0pNAL4gZk0KBw4fSr3ILRaTqFZydS8cNPo1o_ayBXeBUFwKeYhhz1FHMDAaIHWgj8OxhfBui2-Qh0rbAW7VfjizYEB37FfEJgE8JOWQBjMUDnJ5_a_StoBPPO5zErD3uMvKOkcefUmSbrP-FpN68dFvRHkzAsXszt_7BMZdqXMYehjOSPx9V2dz2u5zyek5hh8Hx7K4_QMVdkYu5AfTrguiTiwNY7toWPAVQanMg4mHWunJnnykS3V1uZaWbyWKfXDsyddQinXlnr7UxQzyNEspLWSKK60cEgd0qN8ffkEd4QGWwjfYONizmpsQSxcZnTf155lxAi6wBFL6TfjZjZiI7UhHHmmh0slWOpMgTVmdDGZsnRMLUGzIvdGVC_FDkJX_JfW-yk1h9Pm6_ZxKd-YGpsYH7piRJWh6etCOZZ2yuMsXbO_LA3rSdAMw7DRiOJOUo86cY0tWZokQb3ZbMRRFLWjsBVvamxVxqsH7aSexO1WHLX8X9TZ_AMOB5n7) +```mermaid +sequenceDiagram + participant Browser + participant AppServer as DoczyApiBE + participant Cognito + + Browser->>AppServer: 1. GET /login + Note over AppServer: 2. Generate code_verifier
    Generate code_challenge + AppServer->>Browser: 3. Redirect to Cognito + Browser->>Cognito: 4. GET /oauth2/authorize?...code_challenge + Note over Cognito: 5. Process auth request + Cognito->>Browser: 6. Cognito Login Page + Browser->>Cognito: 7. User credentials + Note over Cognito: 8. Validate credentials + Cognito->>Browser: 9. Redirect with code + Browser->>AppServer: 10. GET /login-callback?code=... + Note over AppServer: 11. Retrieve code_verifier + AppServer->>Cognito: 12. POST /oauth2/token
    code=...&code_verifier=... + Note over Cognito: 13. Validate code and verifier + Cognito->>AppServer: 14. Tokens response + Note over AppServer: 15. Verify tokens
    Check permissions + AppServer->>Browser: 16. Authentication successful +``` \ No newline at end of file diff --git a/internal/server/api/listener.go b/internal/server/api/listener.go index 1371b143..d4a03d1d 100644 --- a/internal/server/api/listener.go +++ b/internal/server/api/listener.go @@ -189,14 +189,8 @@ func New(ctx context.Context, cfg Config) (*Server, error) { cfg.SetRouter(e) // auth start - may move to separate rbac function - routePermissions := map[string][]string{ - "/users": {"exporters", "uploaders", "querybuilders"}, - "/users/:id": {"exporters", "querybuilders"}, - "/orders": {"exporters"}, - "/reports/sales": {"exporters", "uploaders", "querybuilders"}, - "/settings": {"exporters"}, - "/api/inventory/update": {"exporters", "uploaders"}, - } + // update these to match the endpoints. + routePermissions := GetRoutePermissions() cfg.SetAuthRoutePermissions(routePermissions) cognitoauth.RegisterRoutes(cfg.GetRouter(), cfg) diff --git a/internal/server/api/route_permissions.go b/internal/server/api/route_permissions.go new file mode 100644 index 00000000..f61cc014 --- /dev/null +++ b/internal/server/api/route_permissions.go @@ -0,0 +1,11 @@ +package api + +func GetRoutePermissions() map[string][]string { + return map[string][]string{ + "/client": {"exporters", "uploaders", "querybuilders"}, + "/document": {"exporters", "querybuilders"}, + "/query": {"exporters", "uploaders", "querybuilders"}, + "/export": {"exporters"}, + "/settings": {"exporters"}, + } +}