Skip to content

Third Party: add a username/password login page matching the Data Custodian login design #249

Open

Description

@dfcoffin

Summary

Give the Third Party a real login page with the same design as the Data Custodian's: a card with a GBA green header strip, username and password fields, a full-width primary button, and the row of three feature icons underneath. It should sit on the shared GBA layout (fragments/layout, /css/gba-theme.css) like the rest of the TP since #244.

Current state (main, local profile)

  • templates/login.html shows only a "Sign in with Data Custodian" button that links to /oauth2/authorization/datacustodian. That request returns 500: no client registration is named datacustodian (it is only the provider name; the registrations are datacustodian-monthly, datacustodian-daily and datacustodian-admin).
  • SecurityConfiguration configures only oauth2Login. There is no form login, UserDetailsService or PasswordEncoder, so the TP has no accounts of its own.
  • The legacy portal controllers still expect local users: BaseController checks ROLE_CUSTODIAN and ROLE_USER (from RetailCustomerEntity), and web/custodian/AdministratorController and RetailCustomerController are @PreAuthorize("hasRole('ROLE_CUSTODIAN')"). Nothing can ever hold those roles today.

Why the TP needs its own login

In ESPI the Third Party is a separate service provider with its own customers. A customer signs in to the TP first, then, from the TP, authorizes it to fetch their data from a Data Custodian through the AS (/oauth2/authorize/monthly|daily|admin on the TP home page). Signing in to the TP and authorizing a DC are two different steps. Today the TP has only the second, and it is broken.

Proposed scope

  1. Accounts: a TP user store with BCrypt passwords and roles ROLE_USER (TP customer) and ROLE_CUSTODIAN (TP administrator). Mirror the DC: RetailCustomerUserDetailsService, a dedicated customerPasswordEncoder, and a seeded dev admin on the local profile only, like the DC's admin/admin. Decide whether to reuse RetailCustomerEntity from openespi-common, as the legacy TP code assumes, or a TP-specific table.
  2. Security: add formLogin (login page /login, CSRF on, return_to handling) alongside the existing oauth2Login, which is used to authorize DCs, not to sign in. Keep /, /login, /about, /TermsOfService, /UsagePolicy and /error public.
  3. Page: rebuild login.html on the TP layout using the DC login's design and markup (openespi-datacustodian/.../templates/login.html): card + gba-card-header, labelled form-controls, btn-primary w-100, and the three gba-icon feature tiles. Error and logout messages as on the DC.
  4. After login: ROLE_USER lands on the TP customer home (the "Data Access Authorization" cards to authorize a DC) and ROLE_CUSTODIAN on the TP admin page. HomeController already branches on these roles.
  5. Fix the broken button: either remove "Sign in with Data Custodian" from the login page (DC authorization belongs on the home page after login) or point it at a real registration. Also fix the authorization-code registrations' secrets, redirect URIs and scopes, which do not match the AS's seeded third_party client (see the TP bring-up: missing JAXB Atom marshaller, narrow component scan, and broader OAuth2-client wiring gaps #146 comment).
  6. Tests: MockMvc for valid login, invalid login (/login?error), POST without CSRF (403), role-based landing, the page rendering through the GBA layout, and that the login page is public.

References

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions