├── frontend ├── src │ ├── components │ │ ├── ButtonRow │ │ │ ├── index.ts │ │ │ ├── ButtonRow.module.css │ │ │ └── ButtonRow.tsx │ │ ├── RequestPage │ │ │ ├── index.ts │ │ │ ├── RequestPage.module.css │ │ │ └── RequestPage.tsx │ │ ├── RightsError │ │ │ ├── index.ts │ │ │ ├── RightsError.module.css │ │ │ └── RightsError.tsx │ │ ├── RightsList │ │ │ ├── index.ts │ │ │ ├── RightsListLogo.module.css │ │ │ ├── RightsListLogo.tsx │ │ │ └── RightsList.tsx │ │ ├── UserInfoBar │ │ │ ├── index.ts │ │ │ ├── UserInfoBar.module.css │ │ │ └── UserInfoBar.tsx │ │ ├── PageContainer │ │ │ ├── index.ts │ │ │ ├── PageContainer.module.css │ │ │ └── PageContainer.tsx │ │ ├── ActionBar │ │ │ ├── index.ts │ │ │ ├── ActionBarIcon.module.css │ │ │ ├── ActionBarContent.module.css │ │ │ ├── ActionBarIcon.tsx │ │ │ ├── Context.ts │ │ │ ├── ActionBarContent.tsx │ │ │ ├── ActionBarHeader.module.css │ │ │ └── ActionBarHeader.tsx │ │ ├── PageDescription │ │ │ ├── index.ts │ │ │ ├── PageDescription.module.css │ │ │ └── PageDescription.tsx │ │ ├── SystemUserActionBar │ │ │ ├── index.ts │ │ │ ├── SystemUserActionBar.module.css │ │ │ └── SystemUserActionBar.tsx │ │ ├── DelegationCheckError │ │ │ ├── index.ts │ │ │ ├── DelegationCheckError.module.css │ │ │ └── DelegationCheckError.tsx │ │ ├── Page │ │ │ ├── index.ts │ │ │ ├── Page.module.css │ │ │ ├── PageHeader.tsx │ │ │ ├── Page.tsx │ │ │ └── PageHeader.module.css │ │ └── index.ts │ ├── sites │ │ └── NotFoundSite │ │ │ ├── index.ts │ │ │ ├── NotFoundSite.module.css │ │ │ └── NotFoundSite.tsx │ ├── features │ │ ├── creationpage │ │ │ ├── index.ts │ │ │ ├── CreationPageContent.module.css │ │ │ └── CreationPage.tsx │ │ ├── overviewpage │ │ │ ├── index.ts │ │ │ ├── OverviewPageContent.module.css │ │ │ └── OverviewPage.tsx │ │ ├── changeRequestPage │ │ │ ├── index.ts │ │ │ └── ChangeRequestPage.tsx │ │ ├── vendorRequestPage │ │ │ ├── index.ts │ │ │ └── VendorRequestPage.tsx │ │ └── detailpage │ │ │ ├── DetailPage.module.css │ │ │ └── DetailPage.tsx │ ├── routes │ │ ├── paths │ │ │ ├── index.ts │ │ │ └── AuthenticationPath.ts │ │ └── Router │ │ │ └── Router.tsx │ ├── types │ │ ├── systemRight.ts │ │ ├── problemDetail.ts │ │ ├── profileInfo.ts │ │ ├── systemUser.ts │ │ ├── vendorSystem.ts │ │ ├── index.ts │ │ ├── systemUserCreationRequest.ts │ │ ├── changeRequest.ts │ │ └── serviceResource.ts │ ├── vite-env.d.ts │ ├── mocks │ │ └── browser.ts │ ├── assets │ │ ├── Add.svg │ │ ├── Office1.svg │ │ ├── MinusCircle.svg │ │ ├── Cancel.svg │ │ ├── AddCircle.svg │ │ ├── RedClose.svg │ │ ├── Error.svg │ │ ├── Edit.svg │ │ ├── ShakeHands.svg │ │ ├── altinn-logo.svg │ │ ├── Settings.svg │ │ └── Api.svg │ ├── utils │ │ ├── languageUtils.ts │ │ └── urlUtils.ts │ ├── rtk │ │ ├── features │ │ │ ├── userApi.ts │ │ │ └── api.ts │ │ └── app │ │ │ └── store.ts │ ├── resources │ │ ├── css │ │ │ └── Common.css │ │ └── Cookie │ │ │ └── CookieMethods.ts │ └── main.jsx ├── .prettierrc.json ├── entrypoint.js ├── .prettierignore ├── playwright │ ├── config │ │ ├── .env.at21 │ │ ├── .env.tt02 │ │ ├── .env.at22 │ │ ├── .env.at23 │ │ └── .env.at24 │ ├── api-requests │ │ └── global-teardown.tsx │ ├── e2eTests │ │ ├── auth.setup.ts │ │ ├── selectSystemVendor.spec.ts │ │ ├── deleteSystemUser.spec.ts │ │ ├── approveSystemUserRequest.spec.ts │ │ └── approveSystemUserChangeRequest.spec.ts │ ├── package.json │ ├── util │ │ └── TestdataApi.tsx │ ├── pages │ │ ├── loginPage.ts │ │ └── systemUserPage.ts │ └── playwright.config.ts ├── tsconfig.node.json ├── .yarnrc.yml ├── index.html ├── tsconfig.json ├── vite.config.ts ├── eslint.config.js ├── package.json └── config.ts ├── bff ├── src │ └── Altinn.Authentication.UI │ │ ├── Altinn.Authentication.UI │ │ ├── wwwroot │ │ │ └── authentication │ │ │ │ └── .gitkeep │ │ ├── appsettings.Development.json │ │ ├── Models │ │ │ ├── UserProfile │ │ │ │ └── ProfileInfo.cs │ │ │ └── FrontEndEntryPointOptions.cs │ │ ├── Extensions │ │ │ ├── SecurityHeadersApplicationBuilderExtensions.cs │ │ │ └── DataProtectionConfiguration.cs │ │ ├── Filters │ │ │ └── AutoValidateAntiforgeryTokenIfAuthCookie.cs │ │ ├── Health │ │ │ ├── HealthCheck.cs │ │ │ └── HealthTelemetryFilter.cs │ │ ├── Configuration │ │ │ └── CustomTelemetryInitializer.cs │ │ ├── appsettings.PROD.json │ │ ├── appsettings.TT02.json │ │ ├── appsettings.AT21.json │ │ ├── appsettings.AT22.json │ │ ├── appsettings.AT23.json │ │ ├── appsettings.AT24.json │ │ ├── appsettings.json │ │ ├── Middleware │ │ │ └── SecurityHeadersMiddleware.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Altinn.Authentication.UI.csproj │ │ ├── Views │ │ │ └── Home │ │ │ │ └── Index.cshtml │ │ └── Controllers │ │ │ └── SystemRegisterController.cs │ │ ├── Altinn.Authentication.UI.Core │ │ ├── Common │ │ │ ├── Models │ │ │ │ ├── HttpErrorResponse.cs │ │ │ │ └── AuthorizedPartyTypeExternal.cs │ │ │ ├── Rights │ │ │ │ ├── Right.cs │ │ │ │ └── AttributePair.cs │ │ │ ├── Problems │ │ │ │ └── ProblemMapper.cs │ │ │ └── Helpers │ │ │ │ ├── JwtTokenUtil.cs │ │ │ │ └── ProfileHelper.cs │ │ ├── AppConfiguration │ │ │ ├── KeyVaultSettings.cs │ │ │ ├── ClientSettings.cs │ │ │ ├── GeneralSettings.cs │ │ │ ├── CacheConfig.cs │ │ │ └── AppEnvironment.cs │ │ ├── Authentication │ │ │ ├── IAuthenticationClient.cs │ │ │ ├── AltinnCoreClaimType.cs │ │ │ ├── AuthenticationHelper.cs │ │ │ └── JwtTokenUtil.cs │ │ ├── SystemRegister │ │ │ ├── IResourceRegistryClient.cs │ │ │ ├── ISystemRegisterService.cs │ │ │ ├── OrgList.cs │ │ │ ├── Resource │ │ │ │ ├── Keyword.cs │ │ │ │ ├── ResourceType.cs │ │ │ │ ├── ReferenceSource.cs │ │ │ │ ├── ResourcePartyType.cs │ │ │ │ ├── CompetentAuthority.cs │ │ │ │ ├── ContactPoints.cs │ │ │ │ ├── ReferenceType.cs │ │ │ │ └── ResourceReference.cs │ │ │ ├── ISystemRegisterClient.cs │ │ │ ├── IRegisterClient.cs │ │ │ ├── Org.cs │ │ │ ├── RegisteredSystemDTO.cs │ │ │ └── SystemRegisterService.cs │ │ ├── UserProfiles │ │ │ ├── IAccessManagementClient.cs │ │ │ ├── IUserProfileService.cs │ │ │ ├── IUserProfileClient.cs │ │ │ ├── IPartyService.cs │ │ │ ├── UserProfileService.cs │ │ │ └── PartyService.cs │ │ ├── SystemUsers │ │ │ ├── IRequestClient.cs │ │ │ ├── IRequestService.cs │ │ │ ├── IChangeRequestClient.cs │ │ │ ├── IChangeRequestService.cs │ │ │ ├── ISystemUserClient.cs │ │ │ ├── SystemUserRequestDto.cs │ │ │ └── ISystemUserService.cs │ │ └── Altinn.Authentication.UI.Core.csproj │ │ ├── Altinn.Authentication.UI.Mocks │ │ ├── Mocks │ │ │ ├── HomeAndAuth │ │ │ │ ├── AuthenticationNullRefreshMock.cs │ │ │ │ ├── AuthenticationClientMock.cs │ │ │ │ ├── JwtCookiePostConfigureOptions.cs │ │ │ │ └── ConfigurationManagerStub.cs │ │ │ ├── SystemRegister │ │ │ │ ├── RegisterClientMock.cs │ │ │ │ └── ResourceRegistryClientMock.cs │ │ │ └── UserProfiles │ │ │ │ ├── PartyClientMock.cs │ │ │ │ └── UserProfileClientMock.cs │ │ ├── Altinn.Authentication.UI.Mocks.csproj │ │ └── Utils │ │ │ └── JwtTokenMock.cs │ │ ├── Altinn.Authentication.UI.Integration │ │ ├── AccessToken │ │ │ └── IAccessTokenProvider.cs │ │ ├── KeyVault │ │ │ ├── IKeyVaultService.cs │ │ │ ├── KeyVaultService.cs │ │ │ └── LocalKeyVaultService.cs │ │ ├── Altinn.Authentication.UI.Integration.csproj │ │ └── Configuration │ │ │ └── PlatformSettings.cs │ │ ├── .dockerignore │ │ └── Altinn.Authentication.UI.Tests │ │ ├── appsettings.test.json │ │ ├── CustomWebApplicationFactory.cs │ │ ├── Health │ │ └── HealthCheckTest.cs │ │ ├── platform-org.pem │ │ ├── selfSignedTestCertificatePublic.cer │ │ ├── Clients │ │ └── SystemUserClientTest.cs │ │ ├── Controllers │ │ ├── SystemRegisterControllerTest.cs │ │ └── SystemUserControllerTest.cs │ │ └── Altinn.Authentication.UI.Tests.csproj └── README.md ├── renovate.json ├── .github ├── workflows │ ├── build-backend-on-pr.yml │ ├── build-frontend-on-pr.yml │ ├── template-test-playwright.yml │ └── build-deploy-at.yml └── actions │ └── deploy │ ├── action.yml │ └── deploy.mts ├── LICENSE ├── Dockerfile └── README.md /frontend/src/components/ButtonRow/index.ts: -------------------------------------------------------------------------------- 1 | export { ButtonRow } from './ButtonRow'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/RequestPage/index.ts: -------------------------------------------------------------------------------- 1 | export { RequestPage } from './RequestPage'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/RightsError/index.ts: -------------------------------------------------------------------------------- 1 | export { RightsError } from './RightsError'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/RightsList/index.ts: -------------------------------------------------------------------------------- 1 | export { RightsList } from './RightsList'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/UserInfoBar/index.ts: -------------------------------------------------------------------------------- 1 | export { UserInfoBar } from './UserInfoBar'; 2 | -------------------------------------------------------------------------------- /frontend/src/sites/NotFoundSite/index.ts: -------------------------------------------------------------------------------- 1 | export { NotFoundSite } from './NotFoundSite'; 2 | -------------------------------------------------------------------------------- /frontend/src/features/creationpage/index.ts: -------------------------------------------------------------------------------- 1 | export { CreationPage } from './CreationPage'; 2 | -------------------------------------------------------------------------------- /frontend/src/features/overviewpage/index.ts: -------------------------------------------------------------------------------- 1 | export { OverviewPage } from './OverviewPage'; 2 | -------------------------------------------------------------------------------- /frontend/src/routes/paths/index.ts: -------------------------------------------------------------------------------- 1 | export { AuthenticationRoute } from './AuthenticationPath'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/PageContainer/index.ts: -------------------------------------------------------------------------------- 1 | export { PageContainer } from './PageContainer'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/ActionBar/index.ts: -------------------------------------------------------------------------------- 1 | export { ActionBar, type ActionBarProps } from './ActionBar'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/PageDescription/index.ts: -------------------------------------------------------------------------------- 1 | export { PageDescription } from './PageDescription'; 2 | -------------------------------------------------------------------------------- /frontend/src/features/changeRequestPage/index.ts: -------------------------------------------------------------------------------- 1 | export { ChangeRequestPage } from './ChangeRequestPage'; 2 | -------------------------------------------------------------------------------- /frontend/src/features/vendorRequestPage/index.ts: -------------------------------------------------------------------------------- 1 | export { VendorRequestPage } from './VendorRequestPage'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/SystemUserActionBar/index.ts: -------------------------------------------------------------------------------- 1 | export { SystemUserActionBar } from './SystemUserActionBar'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/DelegationCheckError/index.ts: -------------------------------------------------------------------------------- 1 | export { DelegationCheckError } from './DelegationCheckError'; 2 | -------------------------------------------------------------------------------- /frontend/src/components/Page/index.ts: -------------------------------------------------------------------------------- 1 | export { Page } from './Page'; 2 | export { PageHeader } from './PageHeader'; 3 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/wwwroot/authentication/.gitkeep: -------------------------------------------------------------------------------- 1 | /// Empty file to keep git from deleting this folder -------------------------------------------------------------------------------- /frontend/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "auto", 3 | "jsxSingleQuote": true, 4 | "printWidth": 100, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/components/DelegationCheckError/DelegationCheckError.module.css: -------------------------------------------------------------------------------- 1 | .delegationCheckError { 2 | margin-top: var(--ds-size-4); 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/types/systemRight.ts: -------------------------------------------------------------------------------- 1 | export interface SystemRight { 2 | resource: { 3 | id: string; 4 | value: string; 5 | }[]; 6 | } 7 | -------------------------------------------------------------------------------- /frontend/entrypoint.js: -------------------------------------------------------------------------------- 1 | // Entrypoint for production build 2 | // See https://vitejs.dev/guide/backend-integration.html 3 | 4 | import './src/main'; 5 | -------------------------------------------------------------------------------- /frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | .yarn 2 | yarn.lock 3 | .gitignore 4 | *.svg 5 | **/dist/ 6 | *.xml 7 | *.code-workspace 8 | .eslintignore 9 | *.snap 10 | *.yaml -------------------------------------------------------------------------------- /frontend/playwright/config/.env.at21: -------------------------------------------------------------------------------- 1 | ENV_NAME="at21" 2 | BASE_URL="https://at21.altinn.cloud" 3 | SYSYEMUSER_URL="https://authn.ui.at21.altinn.cloud/authfront/ui/auth/creation" -------------------------------------------------------------------------------- /frontend/src/types/problemDetail.ts: -------------------------------------------------------------------------------- 1 | export interface ProblemDetail { 2 | code: string; 3 | detail: string; 4 | status: number; 5 | title: string; 6 | type: string; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | declare module '*.css'; 5 | declare module '*.svg'; 6 | -------------------------------------------------------------------------------- /frontend/src/types/profileInfo.ts: -------------------------------------------------------------------------------- 1 | export interface ProfileInfo { 2 | loggedInPersonName?: string; 3 | representingPartyName?: string; 4 | canCreateSystemUser?: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/components/RightsError/RightsError.module.css: -------------------------------------------------------------------------------- 1 | .noRightsParagraph { 2 | margin: 2rem 0; 3 | font-style: italic; 4 | } 5 | .noRightsParagraphBold { 6 | font-weight: 600; 7 | } 8 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/Common/Models/HttpErrorResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.Common; 2 | 3 | public record HttpErrorResponse (string Status); 4 | -------------------------------------------------------------------------------- /frontend/src/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | // src/mocks/browser.js 2 | import { setupWorker } from 'msw/browser'; 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /frontend/src/components/ButtonRow/ButtonRow.module.css: -------------------------------------------------------------------------------- 1 | .buttonRow { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | gap: var(--ds-size-4); 6 | margin-top: var(--ds-size-15); 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/components/PageDescription/PageDescription.module.css: -------------------------------------------------------------------------------- 1 | .pageDescription { 2 | display: flex; 3 | flex-direction: column; 4 | gap: var(--ds-size-1); 5 | margin-bottom: var(--ds-size-8); 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/features/detailpage/DetailPage.module.css: -------------------------------------------------------------------------------- 1 | .detailPageContent { 2 | display: flex; 3 | flex-direction: column; 4 | gap: var(--ds-size-8); 5 | } 6 | 7 | .nameField { 8 | max-width: 30rem; 9 | } 10 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/features/overviewpage/OverviewPageContent.module.css: -------------------------------------------------------------------------------- 1 | .systemUserHeader { 2 | margin-top: var(--ds-size-12); 3 | } 4 | 5 | .description { 6 | margin-top: var(--ds-size-2); 7 | margin-bottom: var(--ds-size-12); 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { PageContainer } from './PageContainer'; 2 | export { UserInfoBar } from './UserInfoBar'; 3 | export { ActionBar, type ActionBarProps } from './ActionBar'; 4 | export { Page, PageHeader } from './Page'; 5 | -------------------------------------------------------------------------------- /frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/AppConfiguration/KeyVaultSettings.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.AppConfiguration; 2 | 3 | public class KeyVaultSettings 4 | { 5 | 6 | public string SecretUri { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/Authentication/IAuthenticationClient.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.Authentication; 2 | 3 | public interface IAuthenticationClient 4 | { 5 | Task RefreshToken(); 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/assets/Add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/playwright/api-requests/global-teardown.tsx: -------------------------------------------------------------------------------- 1 | import { TestdataApi } from "playwright/util/TestdataApi"; 2 | 3 | async function globalTeardown() { 4 | console.log('Kjører global opprydding...'); 5 | await TestdataApi.removeAllSystemUsers(); 6 | } 7 | 8 | export default globalTeardown; -------------------------------------------------------------------------------- /frontend/src/types/systemUser.ts: -------------------------------------------------------------------------------- 1 | import { ServiceResource } from './serviceResource'; 2 | 3 | export interface SystemUser { 4 | id: string; 5 | integrationTitle: string; 6 | systemId: string; 7 | supplierName: string; 8 | supplierOrgno: string; 9 | created: string; 10 | resources: ServiceResource[]; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/utils/languageUtils.ts: -------------------------------------------------------------------------------- 1 | import { ValidLanguage } from '@/types'; 2 | 3 | export const i18nLanguageToShortLanguageCode = (i18nLanguage: string): ValidLanguage => { 4 | if (i18nLanguage === 'en') { 5 | return 'en'; 6 | } else if (i18nLanguage === 'no_nn') { 7 | return 'nn'; 8 | } 9 | return 'nb'; 10 | }; 11 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Models/UserProfile/ProfileInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Models; 2 | 3 | public sealed record ProfileInfo 4 | { 5 | public string? LoggedInPersonName { get; set; } 6 | public string? RepresentingPartyName { get; set; } 7 | public bool? CanCreateSystemUser { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/AppConfiguration/ClientSettings.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.AppConfiguration; 2 | 3 | public class ClientSettings 4 | { 5 | public string Issuer { get; set; } 6 | 7 | public string App { get; set; } 8 | 9 | public string CertificateName { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/playwright/e2eTests/auth.setup.ts: -------------------------------------------------------------------------------- 1 | import { test as setup } from '@playwright/test'; 2 | import { LoginWithUserPage } from 'playwright/pages/loginPage'; 3 | 4 | setup('Login with TestID', async ({ page }) => { 5 | const login = new LoginWithUserPage(page); 6 | 7 | await login.loginAndChooseReportee('14824497789', 'AKTVERDIG RETORISK APE'); 8 | }); 9 | -------------------------------------------------------------------------------- /frontend/src/assets/Office1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/components/RightsList/RightsListLogo.module.css: -------------------------------------------------------------------------------- 1 | .logoWrapper { 2 | height: 100%; 3 | aspect-ratio: 1 / 1; 4 | overflow: hidden; 5 | position: relative; 6 | display: flex; 7 | align-items: center; 8 | } 9 | 10 | .logoImg { 11 | max-width: 100%; 12 | max-height: 100%; 13 | object-fit: cover; 14 | position: absolute; 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/features/creationpage/CreationPageContent.module.css: -------------------------------------------------------------------------------- 1 | .creationPageContainer { 2 | display: flex; 3 | flex-direction: column; 4 | gap: var(--ds-size-4); 5 | max-width: 37rem; 6 | } 7 | 8 | .inputContainer { 9 | max-width: 27rem; 10 | } 11 | 12 | .successButton { 13 | background-color: var(--ds-color-success-base-default); 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/components/ButtonRow/ButtonRow.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classes from './ButtonRow.module.css'; 3 | 4 | interface ButtonRowProps { 5 | children: React.ReactNode; 6 | } 7 | 8 | export const ButtonRow = ({ children }: ButtonRowProps): React.ReactNode => { 9 | return {children}; 10 | }; 11 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/IResourceRegistryClient.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.Common.Rights; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemRegister; 4 | 5 | public interface IResourceRegistryClient 6 | { 7 | Task> GetResources(List rights, CancellationToken cancellationToken = default); 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/assets/MinusCircle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/rtk/features/userApi.ts: -------------------------------------------------------------------------------- 1 | import { api } from './api'; 2 | import { ProfileInfo } from '@/types'; 3 | 4 | export const userApi = api.injectEndpoints({ 5 | endpoints: (builder) => ({ 6 | getLoggedInUser: builder.query({ 7 | query: () => `profile/user`, 8 | }), 9 | }), 10 | }); 11 | 12 | export const { useGetLoggedInUserQuery } = userApi; 13 | -------------------------------------------------------------------------------- /frontend/src/assets/Cancel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/sites/NotFoundSite/NotFoundSite.module.css: -------------------------------------------------------------------------------- 1 | .flexWrapper { 2 | display: flex; 3 | flex-direction: column; 4 | gap: var(--ds-size-4); 5 | } 6 | 7 | .flexContainer { 8 | display: flex; 9 | gap: var(--ds-size-30); 10 | margin-top: var(--ds-size-12); 11 | } 12 | 13 | @media only screen and (max-width: 576px) { 14 | .rightContainer { 15 | display: none; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/playwright/config/.env.tt02: -------------------------------------------------------------------------------- 1 | ENV_NAME="tt02" 2 | BASE_URL="https://tt02.altinn.no" 3 | SYSYEMUSER_URL="https://authn.ui.tt02.altinn.no/authfront/ui/auth/creation" 4 | API_BASE_URL="https://platform.tt02.altinn.no/authentication/api/" 5 | 6 | ALTINN_PARTY_ID="51573288" 7 | ALTINN_USER_ID="1260880" 8 | PID="14824497789" 9 | ORG="310547891" 10 | SYSTEM_ID="310547891_E2E - Playwright - Authentication" -------------------------------------------------------------------------------- /frontend/src/assets/AddCircle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Mocks/Mocks/HomeAndAuth/AuthenticationNullRefreshMock.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.Authentication; 2 | 3 | namespace Altinn.Authentication.UI.Mocks.Mocks; 4 | 5 | public class AuthenticationNullRefreshMock : IAuthenticationClient 6 | { 7 | public async Task RefreshToken() 8 | { 9 | return null; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/assets/RedClose.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/ISystemRegisterService.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.SystemRegister; 2 | 3 | public interface ISystemRegisterService 4 | { 5 | Task> GetListRegSys(CancellationToken cancellation = default); 6 | Task> GetSystemRights(string systemId, CancellationToken cancellationToken); 7 | } 8 | -------------------------------------------------------------------------------- /frontend/playwright/config/.env.at22: -------------------------------------------------------------------------------- 1 | ENV_NAME="at22" 2 | BASE_URL="https://at22.altinn.cloud" 3 | SYSYEMUSER_URL="https://authn.ui.at22.altinn.cloud/authfront/ui/auth/creation" 4 | API_BASE_URL="https://platform.at22.altinn.cloud/authentication/api/" 5 | 6 | ALTINN_PARTY_ID="51359757" 7 | ALTINN_USER_ID="20010849" 8 | PID="14824497789" 9 | ORG="310547891" 10 | SYSTEM_ID="310547891_E2E - Playwright - Authentication" -------------------------------------------------------------------------------- /frontend/playwright/config/.env.at23: -------------------------------------------------------------------------------- 1 | ENV_NAME="at23" 2 | BASE_URL="https://at23.altinn.cloud" 3 | SYSYEMUSER_URL="https://authn.ui.at23.altinn.cloud/authfront/ui/auth/creation" 4 | API_BASE_URL="https://platform.at23.altinn.cloud/authentication/api/" 5 | 6 | ALTINN_PARTY_ID="51234548" 7 | ALTINN_USER_ID="20020268" 8 | PID="14824497789" 9 | ORG="310547891" 10 | SYSTEM_ID="310547891_E2E - Playwright - Authentication" -------------------------------------------------------------------------------- /frontend/playwright/config/.env.at24: -------------------------------------------------------------------------------- 1 | ENV_NAME="at24" 2 | BASE_URL="https://at24.altinn.cloud" 3 | SYSYEMUSER_URL="https://authn.ui.at24.altinn.cloud/authfront/ui/auth/creation" 4 | API_BASE_URL="https://platform.at24.altinn.cloud/authentication/api/" 5 | 6 | ALTINN_PARTY_ID="51321769" 7 | ALTINN_USER_ID="20020071" 8 | PID="14824497789" 9 | ORG="310547891" 10 | SYSTEM_ID="310547891_E2E - Playwright - Authentication" -------------------------------------------------------------------------------- /frontend/src/components/ActionBar/ActionBarIcon.module.css: -------------------------------------------------------------------------------- 1 | .actionBarIcon { 2 | box-sizing: border-box; 3 | flex-shrink: 0; 4 | } 5 | 6 | .actionBarIcon.open { 7 | transform: rotate(180deg); 8 | } 9 | 10 | .actionBarIcon.medium { 11 | height: var(--ds-size-8); 12 | width: var(--ds-size-8); 13 | } 14 | 15 | .actionBarIcon.large { 16 | height: var(--ds-size-10); 17 | width: var(--ds-size-10); 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/UserProfiles/IAccessManagementClient.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.Common.Models; 2 | 3 | namespace Altinn.Authentication.UI.Core.UserProfiles; 4 | 5 | public interface IAccessManagementClient 6 | { 7 | Task GetPartyFromReporteeListIfExists(int partyId); 8 | 9 | Task GetParty(int partyId); 10 | } 11 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Integration/AccessToken/IAccessTokenProvider.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Integration.AccessToken; 2 | 3 | public interface IAccessTokenProvider 4 | { 5 | /// 6 | /// Gets the access token. 7 | /// 8 | /// An access token as a printable string 9 | public Task GetAccessToken(); 10 | } 11 | -------------------------------------------------------------------------------- /frontend/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | # Documentation for yarn nodeLinker option 2 | # https://yarnpkg.com/configuration/yarnrc#node:Linker 3 | nodeLinker: 'node-modules' 4 | 5 | # yarnPath option has been disabled (compared to other Altinn repos) 6 | # because the documentation claims Corepack is best practice: 7 | # https://yarnpkg.com/configuration/yarnrc#yarnPath 8 | # yarnPath: .yarn/releases/yarn-3.6.3.cjs 9 | checksumBehavior: 'update' 10 | -------------------------------------------------------------------------------- /frontend/src/types/vendorSystem.ts: -------------------------------------------------------------------------------- 1 | import { SystemRight } from './systemRight'; 2 | 3 | export interface VendorSystem { 4 | systemId: string; 5 | systemVendorOrgName: string; 6 | systemVendorOrgNumber: string; 7 | name: { 8 | nb: string; 9 | nn: string; 10 | en: string; 11 | }; 12 | description?: { 13 | nb: string; 14 | nn: string; 15 | en: string; 16 | }; 17 | rights: SystemRight[]; 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/OrgList.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.SystemRegister 2 | { 3 | /// 4 | /// Defines a list of orgs 5 | /// 6 | public class OrgList 7 | { 8 | /// 9 | /// Dictionary of orgs 10 | /// 11 | public Dictionary Orgs { get; set; } = []; 12 | } 13 | } -------------------------------------------------------------------------------- /frontend/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type { SystemUser } from './systemUser'; 2 | export type { SystemRight } from './systemRight'; 3 | export type { VendorSystem } from './vendorSystem'; 4 | export type { SystemUserCreationRequest } from './systemUserCreationRequest'; 5 | export type { ChangeRequest } from './changeRequest'; 6 | export type { ProfileInfo } from './profileInfo'; 7 | export type { ServiceResource, ValidLanguage } from './serviceResource'; 8 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /frontend/src/resources/css/Common.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | :root { 6 | font-family: 'Inter', sans-serif; 7 | } 8 | 9 | @supports (font-variation-settings: normal) { 10 | :root { 11 | font-family: 'Inter', sans-serif; 12 | } 13 | } 14 | 15 | .backgroundColor { 16 | background-color: #1eadf7; /* not defined in designsystemet */ 17 | } 18 | 19 | .unstyledList { 20 | list-style-type: none; 21 | padding: 0; 22 | margin: 0; 23 | } 24 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/AppConfiguration/GeneralSettings.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.AppConfiguration; 2 | 3 | public class GeneralSettings 4 | { 5 | 6 | public string? FrontendBaseUrl { get; set; } 7 | 8 | public string? HostName { get; set; } 9 | 10 | public bool DisableCsrfCheck { get; set; } 11 | 12 | public string? LanguageCookie { get; set; } 13 | 14 | public bool UseMockData { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/assets/Error.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Extensions/SecurityHeadersApplicationBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Middleware; 2 | 3 | namespace Altinn.Authentication.UI.Extensions; 4 | 5 | public static class SecurityHeadersApplicationBuilderExtensions 6 | { 7 | public static IApplicationBuilder UseDefaultSecurityHeaders(this IApplicationBuilder builder) 8 | { 9 | return builder.UseMiddleware(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/resources/Cookie/CookieMethods.ts: -------------------------------------------------------------------------------- 1 | export function getCookie(cname: string) { 2 | const name = cname + '='; 3 | const decodedCookie = decodeURIComponent(document.cookie); 4 | const ca = decodedCookie.split(';'); 5 | for (const cx of ca) { 6 | let c = cx; 7 | while (c.charAt(0) === ' ') { 8 | c = c.substring(1); 9 | } 10 | if (c.indexOf(name) === 0) { 11 | return c.substring(name.length, c.length); 12 | } 13 | } 14 | return ''; 15 | } 16 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/UserProfiles/IUserProfileService.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Platform.Profile.Models; 2 | 3 | namespace Altinn.Authentication.UI.Core.UserProfiles; 4 | 5 | public interface IUserProfileService 6 | { 7 | /// 8 | /// Get the userprofile from the Platform Profile API 9 | /// 10 | /// 11 | /// 12 | Task GetUserProfile(int userid); 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/components/UserInfoBar/UserInfoBar.module.css: -------------------------------------------------------------------------------- 1 | .userInfoBar { 2 | display: flex; 3 | justify-content: space-between; 4 | } 5 | 6 | .userInfoContent { 7 | display: flex; 8 | align-items: center; 9 | gap: var(--ds-size-1); 10 | margin-right: var(--ds-size-1); 11 | } 12 | 13 | .userInfoText { 14 | font-weight: 500; 15 | font-size: 0.875rem; 16 | text-align: right; 17 | } 18 | 19 | .companyIcon { 20 | width: var(--ds-size-7); 21 | height: var(--ds-size-7); 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/components/RightsList/RightsListLogo.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classes from './RightsListLogo.module.css'; 3 | 4 | interface RightsListLogoProps { 5 | logoUrl: string; 6 | altText?: string; 7 | } 8 | 9 | export const RightsListLogo = ({ logoUrl, altText }: RightsListLogoProps): React.ReactNode => { 10 | return ( 11 | 12 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /frontend/src/components/SystemUserActionBar/SystemUserActionBar.module.css: -------------------------------------------------------------------------------- 1 | .rightsHeader { 2 | display: flex; 3 | flex-direction: row; 4 | justify-content: space-between; 5 | align-items: center; 6 | margin-bottom: 1rem; 7 | } 8 | 9 | .icon { 10 | height: 4.25rem; 11 | aspect-ratio: 1 / 1; 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | font-size: 2.75rem; 16 | border-radius: 4px; 17 | background-color: var(--ds-color-info-background-subtle); 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Models/FrontEndEntryPointOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Models; 2 | 3 | public class FrontEndEntryPointOptions 4 | { 5 | public const string SectionName = "entrypoint.js"; 6 | 7 | public string? File {get; set;} 8 | 9 | public string? Src { get; set; } 10 | 11 | public bool IsEntry { get; set; } 12 | 13 | public List Css { get; set; } = new(); 14 | 15 | public List Assets { get; set; } = new(); 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/assets/Edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "local>Altinn/renovate-config" 5 | ], 6 | "labels": [ 7 | "dependencies" 8 | ], 9 | "packageRules": [ 10 | { 11 | "matchPackageNames": [ 12 | "@digdir/designsystemet-css", 13 | "@digdir/designsystemet-react", 14 | "@digdir/designsystemet-theme" 15 | ], 16 | "groupName": "Digdir Designsystemet", 17 | "groupSlug": "digdir-designsystemet" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Mocks/Mocks/SystemRegister/RegisterClientMock.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.SystemRegister; 2 | using Altinn.Platform.Register.Models; 3 | 4 | namespace Altinn.Authentication.UI.Mocks.SystemRegister; 5 | public class RegisterClientMock : IRegisterClient 6 | { 7 | public Task> GetPartyNamesForOrganization(IEnumerable orgNrs, CancellationToken cancellationToken = default) 8 | { 9 | throw new NotImplementedException(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/types/systemUserCreationRequest.ts: -------------------------------------------------------------------------------- 1 | import { ServiceResource } from './serviceResource'; 2 | import { SystemRight } from './systemRight'; 3 | import { VendorSystem } from './vendorSystem'; 4 | 5 | type RequestStatus = 'New' | 'Accepted' | 'Rejected' | 'Denied' | 'Timedout'; 6 | 7 | export interface SystemUserCreationRequest { 8 | id: string; 9 | system: VendorSystem; 10 | systemId: string; 11 | status: RequestStatus; 12 | rights: SystemRight[]; 13 | resources: ServiceResource[]; 14 | redirectUrl?: string; 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/components/Page/Page.module.css: -------------------------------------------------------------------------------- 1 | .page { 2 | width: 100%; 3 | box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.25); 4 | box-sizing: border-box; 5 | } 6 | 7 | .pageContent { 8 | background-color: var(--ds-color-accent-background-default); 9 | box-sizing: inherit; 10 | --component-page-content-padding: var(--ds-size-12); 11 | padding: var(--component-page-content-padding); 12 | } 13 | 14 | @media only screen and (max-width: 769px) { 15 | .pageContent { 16 | --component-page-content-padding: var(--ds-size-2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/types/changeRequest.ts: -------------------------------------------------------------------------------- 1 | import { ServiceResource } from './serviceResource'; 2 | import { SystemRight } from './systemRight'; 3 | import { VendorSystem } from './vendorSystem'; 4 | 5 | type RequestStatus = 'New' | 'Accepted' | 'Rejected' | 'Denied' | 'Timedout'; 6 | 7 | export interface ChangeRequest { 8 | id: string; 9 | system: VendorSystem; 10 | systemId: string; 11 | status: RequestStatus; 12 | requiredRights: SystemRight[]; 13 | unwantedRights: SystemRight[]; 14 | resources: ServiceResource[]; 15 | redirectUrl?: string; 16 | } 17 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/UserProfiles/IUserProfileClient.cs: -------------------------------------------------------------------------------- 1 | 2 | using Altinn.Platform.Profile.Models; 3 | 4 | namespace Altinn.Authentication.UI.Core.UserProfiles; 5 | 6 | /// 7 | /// 8 | /// 9 | public interface IUserProfileClient 10 | { 11 | /// 12 | /// Retrieves the userprofile by id from the Platforms Profile API 13 | /// 14 | /// 15 | /// 16 | public Task GetUserProfile(int userid); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Mocks/Mocks/HomeAndAuth/AuthenticationClientMock.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.Authentication; 2 | using Altinn.Authentication.UI.Mocks.Utils; 3 | 4 | namespace Altinn.Authentication.UI.Mocks.Authentication; 5 | 6 | public class AuthenticationClientMock : IAuthenticationClient 7 | { 8 | public AuthenticationClientMock() 9 | { 10 | 11 | } 12 | public async Task RefreshToken() 13 | { 14 | return PrincipalUtil.GetAccessToken("sbl.authorization"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/components/ActionBar/ActionBarContent.module.css: -------------------------------------------------------------------------------- 1 | .actionBarContent { 2 | border-style: solid; 3 | border-bottom-left-radius: 6px; 4 | border-bottom-right-radius: 6px; 5 | border-width: 1px; 6 | border-color: var(--border-color); 7 | padding: var(--ds-size-10); 8 | display: flex; 9 | flex-direction: column; 10 | gap: var(--ds-size-1); 11 | } 12 | 13 | .actionBarContent.light { 14 | --border-color: var(--ds-color-neutral-border-subtle); 15 | } 16 | 17 | .actionBarContent.neutral { 18 | --border-color: var(--ds-color-neutral-border-subtle); 19 | } 20 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/AppConfiguration/CacheConfig.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.AppConfiguration; 2 | 3 | public class CacheConfig 4 | { 5 | /// 6 | /// Gets or sets the cache timeout (in minutes) for the lookup of party information 7 | /// 8 | public int PartyCacheTimeout { get; set; } 9 | 10 | /// 11 | /// Gets or sets the cache timeout (in minutes) for lookup of resource owners 12 | /// 13 | public int ResourceOwnerCacheTimeout { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/Resource/Keyword.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.SystemRegister 2 | { 3 | /// 4 | /// Model for defining keywords 5 | /// 6 | public class Keyword 7 | { 8 | /// 9 | /// The key word 10 | /// 11 | public required string Word { get; set; } 12 | 13 | /// 14 | /// Language of the key word 15 | /// 16 | public required string Language { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/ISystemRegisterClient.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.Common.Rights; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemRegister; 4 | 5 | public interface ISystemRegisterClient 6 | { 7 | Task> GetListRegSys(CancellationToken cancellationToken = default); 8 | Task GetSystem(string systemId, CancellationToken cancellationToken = default); 9 | Task> GetRightsFromSystem(string systemId, CancellationToken cancellationToken = default); 10 | } 11 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemUsers/IRequestClient.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authorization.ProblemDetails; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemUsers; 4 | 5 | public interface IRequestClient 6 | { 7 | Task> GetVendorRequest(int partyId, Guid requestId, CancellationToken cancellationToken = default); 8 | Task> ApproveRequest(int partyId, Guid requestId, CancellationToken cancellationToken = default); 9 | Task> RejectRequest(int partyId, Guid requestId, CancellationToken cancellationToken = default); 10 | } 11 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemUsers/IRequestService.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authorization.ProblemDetails; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemUsers; 4 | 5 | public interface IRequestService 6 | { 7 | Task> GetVendorRequest(int partyId, Guid requestId, CancellationToken cancellationToken = default); 8 | Task> ApproveRequest(int partyId, Guid requestId, CancellationToken cancellationToken = default); 9 | Task> RejectRequest(int partyId, Guid requestId, CancellationToken cancellationToken = default); 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/features/overviewpage/OverviewPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Page, PageContainer } from '@/components'; 3 | import { OverviewPageContent } from './OverviewPageContent'; 4 | import ApiIcon from '@/assets/Api.svg?react'; 5 | import { useTranslation } from 'react-i18next'; 6 | 7 | export const OverviewPage = () => { 8 | const { t } = useTranslation(); 9 | 10 | return ( 11 | 12 | } title={t('authent_overviewpage.banner_title')}> 13 | 14 | 15 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemUsers/IChangeRequestClient.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authorization.ProblemDetails; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemUsers; 4 | 5 | public interface IChangeRequestClient 6 | { 7 | Task> GetChangeRequest(int partyId, Guid requestId, CancellationToken cancellationToken = default); 8 | Task> ApproveChangeRequest(int partyId, Guid requestId, CancellationToken cancellationToken = default); 9 | Task> RejectChangeRequest(int partyId, Guid requestId, CancellationToken cancellationToken = default); 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/components/Page/PageHeader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cn from 'classnames'; 3 | import classes from './PageHeader.module.css'; 4 | 5 | export interface PageHeaderProps { 6 | children?: React.ReactNode; 7 | icon?: React.JSX.Element; 8 | color: 'dark' | 'light' | 'success' | 'danger'; 9 | } 10 | 11 | export const PageHeader = ({ children, icon, color }: PageHeaderProps) => { 12 | return ( 13 | 14 | {icon} 15 | {children} 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /frontend/src/components/RightsError/RightsError.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Paragraph } from '@digdir/designsystemet-react'; 3 | import { useTranslation } from 'react-i18next'; 4 | import classes from './RightsError.module.css'; 5 | 6 | export const RightsError = (): React.ReactNode => { 7 | const { t } = useTranslation(); 8 | 9 | return ( 10 | 11 | 12 | {t('authent_overviewpage.no_key_role1')}{' '} 13 | 14 | {t('authent_overviewpage.no_key_role2')} 15 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/Altinn.Authentication.UI.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemUsers/IChangeRequestService.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authorization.ProblemDetails; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemUsers; 4 | 5 | public interface IChangeRequestService 6 | { 7 | Task> GetChangeRequest(int partyId, Guid changeRequestId, CancellationToken cancellationToken = default); 8 | Task> ApproveChangeRequest(int partyId, Guid changeRequestId, CancellationToken cancellationToken = default); 9 | Task> RejectChangeRequest(int partyId, Guid changeRequestId, CancellationToken cancellationToken = default); 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/components/PageDescription/PageDescription.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Heading, Paragraph } from '@digdir/designsystemet-react'; 3 | import classes from './PageDescription.module.css'; 4 | 5 | interface PageDescriptionProps { 6 | heading: string; 7 | ingress: string; 8 | } 9 | 10 | export const PageDescription = ({ heading, ingress }: PageDescriptionProps): React.ReactNode => { 11 | return ( 12 | 13 | 14 | {heading} 15 | 16 | {ingress} 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /frontend/src/rtk/app/store.ts: -------------------------------------------------------------------------------- 1 | import { configureStore } from '@reduxjs/toolkit'; 2 | import { createLogger } from 'redux-logger'; 3 | import { api } from '../features/api'; 4 | 5 | const logger = createLogger(); 6 | 7 | const store = configureStore({ 8 | reducer: { 9 | [api.reducerPath]: api.reducer, 10 | }, 11 | middleware: (getDefaultMiddleware) => { 12 | const middleWares = getDefaultMiddleware().concat(api.middleware); 13 | // turn off redux-logger in production 14 | if (!import.meta.env.PROD) { 15 | return middleWares.concat(logger); 16 | } 17 | return middleWares; 18 | }, 19 | }); 20 | 21 | export default store; 22 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/Common/Rights/Right.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.Common.Rights 2 | { 3 | /// 4 | /// Default Right on a Registered System 5 | /// 6 | public class Right 7 | { 8 | /// 9 | /// For instance: Read, Write, Sign 10 | /// 11 | public string? Action { get; set; } 12 | 13 | /// 14 | /// The list of resources at the Service Provider which this Right is for. 15 | /// 16 | public List Resource { get; set; } = []; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/utils/urlUtils.ts: -------------------------------------------------------------------------------- 1 | export const getApiBaseUrl = (): string => { 2 | return '/authfront/api/v1/'; 3 | }; 4 | 5 | export const url = (strings: readonly string[], ...values: readonly string[]): string => { 6 | let result = strings[0]; 7 | for (let i = 1; i < strings.length; i++) { 8 | result += encodeURIComponent(values[i - 1]); 9 | result += strings[i]; 10 | } 11 | 12 | return result; 13 | }; 14 | 15 | export const getHostUrl = (): string => { 16 | return window.location.hostname.replace('authn.ui.', ''); 17 | }; 18 | 19 | export const getLogoutUrl = (): string => { 20 | return `https://${getHostUrl()}/ui/Authentication/Logout`; 21 | }; 22 | -------------------------------------------------------------------------------- /frontend/src/rtk/features/api.ts: -------------------------------------------------------------------------------- 1 | import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; 2 | import { getCookie } from '@/resources/Cookie/CookieMethods'; 3 | import { getApiBaseUrl } from '@/utils/urlUtils'; 4 | 5 | // Define a service using a base URL and expected endpoints 6 | export const api = createApi({ 7 | reducerPath: 'systemUserApi', 8 | baseQuery: fetchBaseQuery({ 9 | baseUrl: getApiBaseUrl(), 10 | prepareHeaders: (headers) => { 11 | headers.set('content-type', 'application/json; charset=utf-8'); 12 | headers.set('X-XSRF-TOKEN', getCookie('XSRF-TOKEN')); 13 | return headers; 14 | }, 15 | }), 16 | endpoints: () => ({}), 17 | }); 18 | -------------------------------------------------------------------------------- /frontend/src/components/ActionBar/ActionBarIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cn from 'classnames'; 3 | import { ChevronDownIcon as Chevron } from '@navikt/aksel-icons'; 4 | 5 | import classes from './ActionBarIcon.module.css'; 6 | import { useActionBarContext } from './Context'; 7 | 8 | export const ActionBarIcon = () => { 9 | const { open, size } = useActionBarContext(); 10 | const iconClassnames = [ 11 | classes.actionBarIcon, 12 | { 13 | [classes.open]: open, 14 | }, 15 | ]; 16 | const props = { 17 | className: cn(iconClassnames, classes[size]), 18 | 'data-testid': 'action-bar-icon', 19 | }; 20 | 21 | return ; 22 | }; 23 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/Resource/ResourceType.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.SystemRegister 2 | { 3 | /// 4 | /// Enum representation of the different types of resources supported by the resource registry 5 | /// 6 | public enum ResourceType 7 | { 8 | 9 | Default = 0, 10 | 11 | Systemresource = 1 << 0, 12 | 13 | MaskinportenSchema = 1 << 1, 14 | 15 | Altinn2Service = 1 << 2, 16 | 17 | AltinnApp = 1 << 3, 18 | 19 | GenericAccessResource = 1 << 4, 20 | 21 | BrokerService = 1 << 5, 22 | 23 | CorrespondenceService = 1 << 6, 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /frontend/src/features/creationpage/CreationPage.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next'; 2 | import React from 'react'; 3 | import { Page, PageContainer } from '@/components'; 4 | import ApiIcon from '@/assets/Api.svg?react'; 5 | import { CreationPageContent } from './CreationPageContent'; 6 | import { AuthenticationRoute } from '@/routes/paths'; 7 | 8 | export const CreationPage = () => { 9 | const { t } = useTranslation(); 10 | 11 | return ( 12 | 13 | } title={t('authent_creationpage.banner_title')}> 14 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Filters/AutoValidateAntiforgeryTokenIfAuthCookie.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.Filters; 2 | 3 | namespace Altinn.Authentication.UI.Filters; 4 | 5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 6 | public class AutoValidateAntiforgeryTokenIfAuthCookie : Attribute, IFilterFactory, IOrderedFilter 7 | { 8 | public bool IsReusable => true; 9 | 10 | public int Order => 1000; 11 | 12 | public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) 13 | { 14 | return serviceProvider.GetRequiredService(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/routes/paths/AuthenticationPath.ts: -------------------------------------------------------------------------------- 1 | enum AuthenticationPath { 2 | Auth = 'auth', 3 | Creation = 'creation', 4 | Overview = 'overview', 5 | Details = 'details', 6 | VendorRequest = 'vendorrequest', 7 | ChangeRequest = 'vendorchangerequest', 8 | } 9 | 10 | export enum AuthenticationRoute { 11 | Overview = `/${AuthenticationPath.Auth}/${AuthenticationPath.Overview}`, 12 | Creation = `/${AuthenticationPath.Auth}/${AuthenticationPath.Creation}`, 13 | Details = `/${AuthenticationPath.Auth}/${AuthenticationPath.Details}`, 14 | VendorRequest = `/${AuthenticationPath.Auth}/${AuthenticationPath.VendorRequest}`, 15 | ChangeRequest = `/${AuthenticationPath.Auth}/${AuthenticationPath.ChangeRequest}`, 16 | } 17 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Tests/appsettings.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "PlatformSettings": { 10 | "PlatformApiBaseUrl": "http://localhost:5117/", 11 | "JwtCookieName": "AltinnStudioRuntime", 12 | "OpenIdWellKnownEndpoint": "http://localhost:5101/authentication/api/v1/openid/" 13 | }, 14 | "CacheConfig": { 15 | "PartyCacheTimeout": 10, 16 | "ResourceRegistryResourceCacheTimeout": 10, 17 | "ResourceOwnerCacheTimeout": 10 18 | }, 19 | "ResourceRegistrySettings": { 20 | "BaseApiUrl": "http://localhost:5101/" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/AppConfiguration/AppEnvironment.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.AppConfiguration; 2 | 3 | public class AppEnvironment 4 | { 5 | 6 | /// 7 | /// Gets an environment variable by its key if it exists otherwise use fallback value 8 | /// 9 | /// 10 | /// 11 | /// 12 | public static string GetVariable(string key, string fallback = "") 13 | { 14 | var value = Environment.GetEnvironmentVariable(key); 15 | 16 | if(value is not null && value.Length > 0) 17 | { 18 | return value; 19 | } 20 | 21 | return fallback; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/IRegisterClient.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Platform.Register.Models; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemRegister; 4 | 5 | /// 6 | /// Interface for client wrapper for integration with the platform register API 7 | /// 8 | public interface IRegisterClient 9 | { 10 | /// 11 | /// Looks up party names of organizations based on organization numbers 12 | /// 13 | /// List of organization numbers 14 | /// 15 | /// Party information 16 | /// 17 | Task> GetPartyNamesForOrganization(IEnumerable orgNrs, CancellationToken cancellationToken = default); 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Integration/KeyVault/IKeyVaultService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Altinn.Authentication.UI.Integration.KeyVault 4 | { 5 | /// 6 | /// Interface for interacting with key vault 7 | /// 8 | public interface IKeyVaultService 9 | { 10 | /// 11 | /// Gets the value of a secret from the given key vault. 12 | /// 13 | /// The URI of the key vault to ask for secret. 14 | /// The id of the secret. 15 | /// The secret value. 16 | Task GetCertificateAsync(string vaultUri, string secretId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Altinn 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /frontend/src/components/ActionBar/Context.ts: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from 'react'; 2 | 3 | export type ClickHandler = () => void; 4 | 5 | export const ActionBarContext = createContext< 6 | | { 7 | open: boolean; 8 | toggleOpen: ClickHandler | undefined; 9 | headerId: string; 10 | contentId: string; 11 | color: 'light' | 'dark' | 'neutral' | 'warning' | 'success' | 'danger'; 12 | size: 'small' | 'medium' | 'large'; 13 | } 14 | | undefined 15 | >(undefined); 16 | 17 | export const useActionBarContext = () => { 18 | const context = useContext(ActionBarContext); 19 | if (context === undefined) { 20 | throw new Error('useActionBarContext must be used within an ActionBarContext'); 21 | } 22 | 23 | return context; 24 | }; 25 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/UserProfiles/IPartyService.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.Common.Models; 2 | using Altinn.Platform.Register.Models; 3 | 4 | namespace Altinn.Authentication.UI.Core.UserProfiles; 5 | 6 | public interface IPartyService 7 | { 8 | /// 9 | /// Retrieves the party if it exists in the authenticated user's list 10 | /// 11 | /// 12 | /// 13 | Task GetPartyFromReporteeListIfExists(int partyId); 14 | 15 | /// 16 | /// Retrieves the party 17 | /// 18 | /// 19 | /// 20 | Task GetParty(int partyId); 21 | } 22 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/Resource/ReferenceSource.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemRegister 4 | { 5 | /// 6 | /// Enum for the different reference sources for resources in the resource registry 7 | /// 8 | public enum ReferenceSource : int 9 | { 10 | [EnumMember(Value = "Default")] 11 | Default = 0, 12 | 13 | [EnumMember(Value = "Altinn1")] 14 | Altinn1 = 1, 15 | 16 | [EnumMember(Value = "Altinn2")] 17 | Altinn2 = 2, 18 | 19 | [EnumMember(Value = "Altinn3")] 20 | Altinn3 = 3, 21 | 22 | [EnumMember(Value = "ExternalPlatform")] 23 | ExternalPlatform = 4 24 | } 25 | } -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Health/HealthCheck.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Diagnostics.HealthChecks; 2 | 3 | namespace Altinn.Authentication.UI.Health; 4 | 5 | public class HealthCheck : IHealthCheck 6 | { 7 | /// 8 | /// TODO: expand the healthcheck to verify that it has access to the "Real" Authentication Component. 9 | /// 10 | /// 11 | /// 12 | /// 13 | public Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken ) 14 | { 15 | return Task.FromResult( 16 | HealthCheckResult.Healthy("BFF for Authentication Frontent is healthy.")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/Resource/ResourcePartyType.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Altinn.Authentication.UI.Core.SystemRegister 5 | { 6 | [JsonConverter(typeof(JsonStringEnumConverter))] 7 | public enum ResourcePartyType 8 | { 9 | [EnumMember(Value = "PrivatePerson")] 10 | PrivatePerson = 0, 11 | 12 | [EnumMember(Value = "LegalEntityEnterprise")] 13 | LegalEntityEnterprise = 1, 14 | 15 | [EnumMember(Value = "Company")] 16 | Company = 2, 17 | 18 | [EnumMember(Value = "BankruptcyEstate")] 19 | BankruptcyEstate = 3, 20 | 21 | [EnumMember(Value = "SelfRegisteredUser")] 22 | SelfRegisteredUser = 4 23 | } 24 | } -------------------------------------------------------------------------------- /frontend/playwright/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playwright", 3 | "version": "1.0.0", 4 | "description": "", 5 | "packageManager": "yarn@4.10.3", 6 | "main": "index.js", 7 | "scripts": { 8 | "env:AT21": "cross-env environment=at21 npx playwright test", 9 | "env:AT22": "cross-env environment=at22 npx playwright test", 10 | "env:AT23": "cross-env environment=at23 npx playwright test", 11 | "env:AT24": "cross-env environment=at24 npx playwright test", 12 | "env:TT02": "cross-env environment=tt02 npx playwright test" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "devDependencies": { 18 | "@playwright/test": "^1.43.1", 19 | "@types/node": "^22.0.0", 20 | "dotenv": "^16.4.5" 21 | }, 22 | "dependencies": { 23 | "cross-env": "^7.0.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/components/Page/Page.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import classes from './Page.module.css'; 3 | import { PageHeader } from './'; 4 | 5 | export interface PageProps { 6 | children?: React.ReactNode; 7 | icon?: React.JSX.Element; 8 | title?: string; 9 | color?: 'dark' | 'light' | 'success' | 'danger'; 10 | } 11 | 12 | export const Page = ({ children, icon, title, color = 'dark' }: PageProps) => { 13 | useEffect(() => { 14 | document.title = title ? `${title} - Altinn` : 'Altinn'; 15 | }, [title]); 16 | 17 | return ( 18 | 19 | {title && ( 20 | 21 | {title} 22 | 23 | )} 24 | {children} 25 | 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemUsers/ISystemUserClient.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authorization.ProblemDetails; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemUsers; 4 | 5 | public interface ISystemUserClient 6 | { 7 | Task GetSpecificSystemUserReal(int partyId, Guid id, CancellationToken cancellationToken = default); 8 | Task> CreateSystemUser(int partyId, SystemUserRequestDto newSystemUser, CancellationToken cancellation = default); 9 | Task> DeleteSystemUserReal(int partyId, Guid id, CancellationToken cancellationToken = default); 10 | Task ChangeSystemUserRealTitle(string newTitle, Guid id, CancellationToken cancellationToken = default); 11 | Task> GetSystemUserRealsForChosenUser(int id, CancellationToken cancellationToken = default); 12 | } 13 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/UserProfiles/UserProfileService.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Platform.Profile.Models; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Altinn.Authentication.UI.Core.UserProfiles; 5 | 6 | public class UserProfileService : IUserProfileService 7 | { 8 | private readonly ILogger _logger; 9 | private readonly IUserProfileClient _profileClient; 10 | 11 | public UserProfileService( 12 | ILogger logger, 13 | IUserProfileClient profileClient) 14 | { 15 | _logger = logger; 16 | _profileClient = profileClient; 17 | } 18 | 19 | /// 20 | public async Task GetUserProfile(int userid) 21 | { 22 | UserProfile userProfile = await _profileClient.GetUserProfile(userid); 23 | return userProfile; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Integration/Altinn.Authentication.UI.Integration.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Tests/CustomWebApplicationFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Mvc.Testing; 4 | using Microsoft.AspNetCore.TestHost; 5 | using Microsoft.Extensions.Configuration; 6 | 7 | namespace Altinn.Authentication.UI.Tests 8 | { 9 | public class CustomWebApplicationFactory : WebApplicationFactory 10 | where TStartup : class 11 | { 12 | protected override void ConfigureWebHost(IWebHostBuilder builder) 13 | { 14 | builder.ConfigureAppConfiguration(config => 15 | { 16 | config.AddConfiguration(new ConfigurationBuilder() 17 | .AddJsonFile("appsettings.test.json") 18 | .Build()); 19 | }); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Configuration/CustomTelemetryInitializer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ApplicationInsights.Channel; 2 | using Microsoft.ApplicationInsights.Extensibility; 3 | 4 | namespace Altinn.Authentiation.UI.Configuration 5 | { 6 | /// 7 | /// Set up custom telemetry for Application Insights 8 | /// 9 | public class CustomTelemetryInitializer : ITelemetryInitializer 10 | { 11 | /// 12 | /// Custom TelemetryInitializer that sets some specific values for the component 13 | /// 14 | public void Initialize(ITelemetry telemetry) 15 | { 16 | if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleName)) 17 | { 18 | telemetry.Context.Cloud.RoleName = "authentication-ui"; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/Resource/CompetentAuthority.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.SystemRegister 2 | { 3 | /// 4 | /// Model representation of Competent Authority part of the ServiceResource model 5 | /// 6 | public class CompetentAuthority 7 | { 8 | /// 9 | /// The organization number 10 | /// 11 | public string? Organization { get; set; } 12 | 13 | /// 14 | /// The organization code 15 | /// 16 | public string? Orgcode { get; set; } 17 | 18 | /// 19 | /// The organization name. If not set it will be retrived from register based on Organization number 20 | /// 21 | public Dictionary? Name { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Mocks/Altinn.Authentication.UI.Mocks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /frontend/src/assets/ShakeHands.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/appsettings.PROD.json: -------------------------------------------------------------------------------- 1 | { 2 | "PlatformSettings": { 3 | "ApiAccessManagementEndpoint": "https://platform.altinn.no/accessmanagement/api/v1/", 4 | "ApiAuthenticationEndpoint": "https://platform.altinn.no/authentication/api/v1/", 5 | "ApiProfileEndpoint": "https://platform.altinn.no/profile/api/v1/", 6 | "OpenIdWellKnownEndpoint": "https://platform.altinn.no/authentication/api/v1/openid/", 7 | "ApiRegisterEndpoint": "https://platform.altinn.no/register/api/v1/", 8 | "ResourceRegistryEndpoint": "https://platform.altinn.no/resourceregistry/api/v1/" 9 | }, 10 | "GeneralSettings": { 11 | "FrontendBaseUrl": "https://authn.ui.altinn.no", 12 | "Hostname": "altinn.no", 13 | "UseMockData": false 14 | }, 15 | "KeyVaultSettings": { 16 | "SecretUri": "https://altinn-prod-authnui-kv.vault.azure.net/" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/Resource/ContactPoints.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.SystemRegister 2 | { 3 | /// 4 | /// Defines a contact point 5 | /// 6 | public class ContactPoint 7 | { 8 | /// 9 | /// The type of contact point, phone, email ++ 10 | /// 11 | public string? Category { get; set; } 12 | 13 | /// 14 | /// The contact details. The actual phone number, email adress 15 | /// 16 | public string? Email { get; set; } 17 | 18 | /// 19 | /// Phone details 20 | /// 21 | public string? Telephone { get; set; } 22 | 23 | /// 24 | /// Contact page 25 | /// 26 | public string? ContactPage { get; set; } 27 | } 28 | } -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react", 18 | "baseUrl": "./", 19 | "paths": { 20 | "@/*": ["./src/*"] 21 | }, 22 | "plugins": [{ "name": "typescript-plugin-css-modules" }] 23 | }, 24 | "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/.eslintrc.js"], 25 | "exclude": ["node_modules", "dist", "eslint.config.js", "vite.config.ts"], 26 | "references": [{ "path": "./tsconfig.node.json" }] 27 | } 28 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/appsettings.TT02.json: -------------------------------------------------------------------------------- 1 | { 2 | "PlatformSettings": { 3 | "ApiAccessManagementEndpoint": "https://platform.tt02.altinn.no/accessmanagement/api/v1/", 4 | "ApiAuthenticationEndpoint": "https://platform.tt02.altinn.no/authentication/api/v1/", 5 | "ApiProfileEndpoint": "https://platform.tt02.altinn.no/profile/api/v1/", 6 | "OpenIdWellKnownEndpoint": "https://platform.tt02.altinn.no/authentication/api/v1/openid/", 7 | "ApiRegisterEndpoint": "https://platform.tt02.altinn.no/register/api/v1/", 8 | "ResourceRegistryEndpoint": "https://platform.tt02.altinn.no/resourceregistry/api/v1/" 9 | }, 10 | "GeneralSettings": { 11 | "FrontendBaseUrl": "https://authn.ui.tt02.altinn.no", 12 | "Hostname": "tt02.altinn.no", 13 | "UseMockData": false 14 | }, 15 | "KeyVaultSettings": { 16 | "SecretUri": "https://altinn-tt02-authnui-kv.vault.azure.net/" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/appsettings.AT21.json: -------------------------------------------------------------------------------- 1 | { 2 | "PlatformSettings": { 3 | "ApiAccessManagementEndpoint": "https://platform.at21.altinn.cloud/accessmanagement/api/v1/", 4 | "ApiAuthenticationEndpoint": "https://platform.at21.altinn.cloud/authentication/api/v1/", 5 | "ApiProfileEndpoint": "https://platform.at21.altinn.cloud/profile/api/v1/", 6 | "OpenIdWellKnownEndpoint": "https://platform.at21.altinn.cloud/authentication/api/v1/openid/", 7 | "ApiRegisterEndpoint": "https://platform.at21.altinn.cloud/register/api/v1/", 8 | "ResourceRegistryEndpoint": "https://platform.at21.altinn.cloud/resourceregistry/api/v1/" 9 | }, 10 | "GeneralSettings": { 11 | "FrontendBaseUrl": "https://authn.ui.at21.altinn.cloud", 12 | "Hostname": "at21.altinn.cloud", 13 | "UseMockData": false 14 | }, 15 | "KeyVaultSettings": { 16 | "SecretUri": "https://altinn-at21-authnui-kv.vault.azure.net/" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/appsettings.AT22.json: -------------------------------------------------------------------------------- 1 | { 2 | "PlatformSettings": { 3 | "ApiAccessManagementEndpoint": "https://platform.at22.altinn.cloud/accessmanagement/api/v1/", 4 | "ApiAuthenticationEndpoint": "https://platform.at22.altinn.cloud/authentication/api/v1/", 5 | "ApiProfileEndpoint": "https://platform.at22.altinn.cloud/profile/api/v1/", 6 | "ApiRegisterEndpoint": "https://platform.at22.altinn.cloud/register/api/v1/", 7 | "OpenIdWellKnownEndpoint": "https://platform.at22.altinn.cloud/authentication/api/v1/openid/", 8 | "ResourceRegistryEndpoint": "https://platform.at22.altinn.cloud/resourceregistry/api/v1/" 9 | }, 10 | "GeneralSettings": { 11 | "FrontendBaseUrl": "https://authn.ui.at22.altinn.cloud", 12 | "Hostname": "at22.altinn.cloud", 13 | "UseMockData": false 14 | }, 15 | "KeyVaultSettings": { 16 | "SecretUri": "https://altinn-at22-authnui-kv.vault.azure.net/" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/appsettings.AT23.json: -------------------------------------------------------------------------------- 1 | { 2 | "PlatformSettings": { 3 | "ApiAccessManagementEndpoint": "https://platform.at23.altinn.cloud/accessmanagement/api/v1/", 4 | "ApiAuthenticationEndpoint": "https://platform.at23.altinn.cloud/authentication/api/v1/", 5 | "ApiProfileEndpoint": "https://platform.at23.altinn.cloud/profile/api/v1/", 6 | "OpenIdWellKnownEndpoint": "https://platform.at23.altinn.cloud/authentication/api/v1/openid/", 7 | "ApiRegisterEndpoint": "https://platform.at23.altinn.cloud/register/api/v1/", 8 | "ResourceRegistryEndpoint": "https://platform.at23.altinn.cloud/resourceregistry/api/v1/" 9 | }, 10 | "GeneralSettings": { 11 | "FrontendBaseUrl": "https://authn.ui.at23.altinn.cloud", 12 | "Hostname": "at23.altinn.cloud", 13 | "UseMockData": false 14 | }, 15 | "KeyVaultSettings": { 16 | "SecretUri": "https://altinn-at23-authnui-kv.vault.azure.net/" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/appsettings.AT24.json: -------------------------------------------------------------------------------- 1 | { 2 | "PlatformSettings": { 3 | "ApiAccessManagementEndpoint": "https://platform.at24.altinn.cloud/accessmanagement/api/v1/", 4 | "ApiAuthenticationEndpoint": "https://platform.at24.altinn.cloud/authentication/api/v1/", 5 | "ApiProfileEndpoint": "https://platform.at24.altinn.cloud/profile/api/v1/", 6 | "OpenIdWellKnownEndpoint": "https://platform.at24.altinn.cloud/authentication/api/v1/openid/", 7 | "ApiRegisterEndpoint": "https://platform.at24.altinn.cloud/register/api/v1/", 8 | "ResourceRegistryEndpoint": "https://platform.at24.altinn.cloud/resourceregistry/api/v1/" 9 | }, 10 | "GeneralSettings": { 11 | "FrontendBaseUrl": "https://authn.ui.at24.altinn.cloud", 12 | "Hostname": "at24.altinn.cloud", 13 | "UseMockData": false 14 | }, 15 | "KeyVaultSettings": { 16 | "SecretUri": "https://altinn-at24-authnui-kv.vault.azure.net/" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/components/ActionBar/ActionBarContent.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cn from 'classnames'; 3 | 4 | import classes from './ActionBarContent.module.css'; 5 | import { useActionBarContext } from './Context'; 6 | import { type ActionBarProps } from './ActionBar'; 7 | 8 | export type ActionBarContentProps = Pick; 9 | 10 | export const ActionBarContent = ({ children }: ActionBarContentProps): React.ReactNode => { 11 | const { open, contentId, headerId, color, size } = useActionBarContext(); 12 | 13 | return ( 14 | <> 15 | {open && ( 16 | 22 | {children} 23 | 24 | )} 25 | > 26 | ); 27 | }; 28 | 29 | ActionBarContent.displayName = 'ActionBarContent'; 30 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/Common/Rights/AttributePair.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Altinn.Authentication.UI.Core.Common.Rights 5 | { 6 | /// 7 | /// This model describes a pair of AttributeId and AttributeValue for use in matching in XACML policies, 8 | /// for instance a resource, a user, a party or an action. 9 | /// 10 | public class AttributePair 11 | { 12 | /// 13 | /// Gets or sets the attribute id for the match 14 | /// 15 | [Required] 16 | [JsonPropertyName("id")] 17 | public string Id { get; set; } 18 | 19 | /// 20 | /// Gets or sets the attribute value for the match 21 | /// 22 | [Required] 23 | [JsonPropertyName("value")] 24 | public string Value { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/Org.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemRegister 4 | { 5 | /// 6 | /// Describes an organization 7 | /// 8 | public class Org 9 | { 10 | public required Dictionary Name { get; set; } 11 | 12 | /// 13 | /// The logo 14 | /// 15 | public string? Logo { get; set; } 16 | 17 | /// 18 | /// The organization number 19 | /// 20 | public required string Orgnr { get; set; } 21 | 22 | /// 23 | /// The homepage 24 | /// 25 | public string? Homepage { get; set; } 26 | 27 | /// 28 | /// The environments available for the organzation 29 | /// 30 | public List? Environments { get; set; } 31 | } 32 | } -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/UserProfiles/PartyService.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.Common.Models; 2 | using Altinn.Platform.Register.Models; 3 | 4 | namespace Altinn.Authentication.UI.Core.UserProfiles; 5 | 6 | public class PartyService : IPartyService 7 | { 8 | private readonly IAccessManagementClient _partyLookUpClient; 9 | 10 | public PartyService(IAccessManagementClient partyLookUpClient) 11 | { 12 | _partyLookUpClient = partyLookUpClient; 13 | } 14 | 15 | public async Task GetPartyFromReporteeListIfExists(int partyId) 16 | { 17 | AuthorizedPartyExternal party = await _partyLookUpClient.GetPartyFromReporteeListIfExists(partyId); 18 | return party; 19 | } 20 | 21 | public async Task GetParty(int partyId) 22 | { 23 | PartyExternal party = await _partyLookUpClient.GetParty(partyId); 24 | return party; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/Resource/ReferenceType.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemRegister 4 | { 5 | /// 6 | /// Enum for reference types of resources in the resource registry 7 | /// 8 | public enum ReferenceType : int 9 | { 10 | [EnumMember(Value = "Default")] 11 | Default = 0, 12 | 13 | [EnumMember(Value = "Uri")] 14 | Uri = 1, 15 | 16 | [EnumMember(Value = "DelegationSchemeId")] 17 | DelegationSchemeId = 2, 18 | 19 | [EnumMember(Value = "MaskinportenScope")] 20 | MaskinportenScope = 3, 21 | 22 | [EnumMember(Value = "ServiceCode")] 23 | ServiceCode = 4, 24 | 25 | [EnumMember(Value = "ServiceEditionCode")] 26 | ServiceEditionCode = 5, 27 | 28 | [EnumMember(Value = "ApplicationId")] 29 | ApplicationId = 6, 30 | } 31 | } -------------------------------------------------------------------------------- /frontend/src/assets/altinn-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Mocks/Mocks/UserProfiles/PartyClientMock.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.Common.Models; 2 | using Altinn.Authentication.UI.Core.Common.Rights; 3 | using Altinn.Authentication.UI.Core.SystemUsers; 4 | using Altinn.Authentication.UI.Core.UserProfiles; 5 | 6 | namespace Altinn.Authentication.UI.Mocks.UserProfiles; 7 | 8 | public class PartyClientMock : IAccessManagementClient 9 | 10 | { 11 | public async Task GetPartyFromReporteeListIfExists(int partyId) 12 | { 13 | AuthorizedPartyExternal mock = new() 14 | { 15 | PartyId = 5001, 16 | OrganizationNumber = "123456789", 17 | Name = "Framifrå Verksemd AS" 18 | }; 19 | 20 | return mock; 21 | } 22 | 23 | public async Task GetParty(int partyId) 24 | { 25 | return new() 26 | { 27 | PartyId = partyId, 28 | Name = "TestUserName" 29 | }; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Mocks/Mocks/SystemRegister/ResourceRegistryClientMock.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.Common.Rights; 2 | using Altinn.Authentication.UI.Core.SystemRegister; 3 | 4 | namespace Altinn.Authentication.UI.Mocks.SystemRegister; 5 | 6 | public class ResourceRegistryClientMock : IResourceRegistryClient 7 | { 8 | private static async Task MockTestHelper() 9 | { 10 | await Task.Delay(250); 11 | 12 | ServiceResource resource1 = new() 13 | { 14 | Identifier = "test", 15 | }; 16 | 17 | return resource1; 18 | } 19 | 20 | public async Task GetResource(string resourceId, CancellationToken cancellationToken = default) 21 | { 22 | return await MockTestHelper(); 23 | } 24 | 25 | public Task> GetResources(List rights, CancellationToken cancellationToken = default) 26 | { 27 | throw new NotImplementedException(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemRegister/Resource/ResourceReference.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Altinn.Authentication.UI.Core.SystemRegister 5 | { 6 | /// 7 | /// Model representation of the resource reference part of the ServiceResource model 8 | /// 9 | public class ResourceReference 10 | { 11 | //// 12 | /// The source the reference identifier points to 13 | /// 14 | [JsonConverter(typeof(JsonStringEnumConverter))] 15 | public ReferenceSource? ReferenceSource { get; set; } 16 | 17 | /// 18 | /// The reference identifier 19 | /// 20 | public string? Reference { get; set; } 21 | 22 | /// 23 | /// The reference type 24 | /// 25 | [JsonConverter(typeof(JsonStringEnumConverter))] 26 | public ReferenceType? ReferenceType { get; set; } 27 | } 28 | } -------------------------------------------------------------------------------- /frontend/playwright/util/TestdataApi.tsx: -------------------------------------------------------------------------------- 1 | import { ApiRequests } from '../api-requests/ApiRequests'; // Adjust the path based on your project structure 2 | 3 | export class TestdataApi { 4 | static async removeAllSystemUsers() { 5 | const api = new ApiRequests(); 6 | 7 | try { 8 | //cleanup method, dont fail test if this fails but log it 9 | const resp = await api.getSystemUsers(); 10 | const users = JSON.parse(resp); 11 | 12 | if (users.length > 0) { 13 | await api.cleanUpSystemUsers(users); 14 | } 15 | } catch (error) { 16 | console.error('Error during cleanup:', error); 17 | } 18 | } 19 | 20 | static async removeSystem(systemName: string) { 21 | const api = new ApiRequests(); 22 | await api.deleteSystemInSystemRegister(systemName); 23 | } 24 | 25 | static generateExternalRef() { 26 | const randomString = Date.now(); // Current timestamp in milliseconds 27 | const randomNum = Math.random().toString(36); 28 | return `${randomNum}${randomString}`; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /frontend/src/components/PageContainer/PageContainer.module.css: -------------------------------------------------------------------------------- 1 | .pageContainer { 2 | margin-left: auto; 3 | margin-right: auto; 4 | min-width: 280px; 5 | max-width: 1056px; 6 | width: 100%; 7 | } 8 | 9 | .buttonContainer { 10 | margin-top: var(--ds-size-8); 11 | display: flex; 12 | justify-content: space-between; 13 | margin-bottom: var(--ds-size-2); 14 | } 15 | 16 | .buttonContainerButton { 17 | border-radius: 50%; 18 | background-color: var(--ds-color-accent-background-default); 19 | } 20 | .buttonContainerButton:last-child { 21 | margin-left: auto; 22 | } 23 | 24 | .buttonContainerIcon { 25 | height: var(--ds-size-6); 26 | width: var(--ds-size-6); 27 | } 28 | 29 | @media only screen and (min-width: 375px) { 30 | .pageMargin { 31 | margin: var(--ds-size-2); 32 | } 33 | } 34 | 35 | @media only screen and (min-width: 769px) { 36 | .pageMargin { 37 | margin: var(--ds-size-4); 38 | } 39 | } 40 | 41 | @media only screen and (min-width: 992px) { 42 | .pageMargin { 43 | margin: var(--ds-size-10); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /.github/workflows/build-backend-on-pr.yml: -------------------------------------------------------------------------------- 1 | name: Build backend 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [main] 7 | paths-ignore: 8 | - frontend/** 9 | 10 | pull_request: 11 | types: [opened, synchronize, reopened] 12 | paths-ignore: 13 | - frontend/** 14 | 15 | env: 16 | dotnet_version: 9.0.x 17 | 18 | jobs: 19 | build: 20 | name: Build 21 | if: ((github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false) || github.event_name == 'push') && github.repository_owner == 'Altinn' && github.actor != 'dependabot[bot]' 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 25 | name: "Checkout Repository" 26 | - uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5 27 | name: Install .NET ${{ env.dotnet_version }} 28 | with: 29 | dotnet-version: ${{ env.dotnet_version }} 30 | - name: Build 31 | run: dotnet build bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.sln 32 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/Common/Models/AuthorizedPartyTypeExternal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | 8 | namespace Altinn.Authentication.UI.Core.Common.Models 9 | { 10 | /// 11 | /// Enum for different types of Authorized Party 12 | /// 13 | [JsonConverter(typeof(JsonStringEnumConverter))] 14 | public enum AuthorizedPartyTypeExternal 15 | { 16 | /// 17 | /// Unknown or unspecified 18 | /// 19 | None = 0, 20 | 21 | /// 22 | /// Party Type is a Person 23 | /// 24 | Person = 1, 25 | 26 | /// 27 | /// Party Type is an Organization 28 | /// 29 | Organization = 2, 30 | 31 | /// 32 | /// Party Type is a Self Identified user 33 | /// 34 | SelfIdentified = 3 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/triple-slash-reference 2 | /// 3 | 4 | import path from 'path'; 5 | 6 | import { defineConfig } from 'vite'; 7 | import react from '@vitejs/plugin-react'; 8 | import svgr from 'vite-plugin-svgr'; 9 | 10 | // https://vitejs.dev/config/ 11 | export default defineConfig({ 12 | resolve: { 13 | alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }], 14 | }, 15 | plugins: [svgr(), react()], 16 | build: { 17 | target: 'es2020', 18 | manifest: 'manifest.json', 19 | rollupOptions: { 20 | // overwrite default .html entry 21 | input: './entrypoint.js', 22 | output: { 23 | entryFileNames: 'assets/authfront.js', 24 | assetFileNames: (assetInfo) => { 25 | const extType = assetInfo.name.split('.')[1]; 26 | if (/css/i.test(extType)) { 27 | return `assets/authfront.css`; 28 | } 29 | return `assets/[name]-[hash][extname]`; 30 | }, 31 | }, 32 | }, 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/Authentication/AltinnCoreClaimType.cs: -------------------------------------------------------------------------------- 1 | namespace Altinn.Authentication.UI.Core.Authentication; 2 | 3 | /// 4 | /// The different Claim types used by the HttpContext.User 5 | /// 6 | public static class AltinnCoreClaimType 7 | { 8 | public const string AuthenticationLevel = "urn:altinn:authlevel"; 9 | 10 | public const string UserId = "urn:altinn:userid"; 11 | 12 | public const string PartyId = "urn:altinn:partyid"; 13 | 14 | public const string RepresentingPartyId = "urn:altinn:representingpartyid"; 15 | 16 | public const string UserName = "urn:altinn:username"; 17 | 18 | public const string Developer = "urn:altinn:developer"; 19 | 20 | public const string DeveloperToken = "urn:altinn:developertoken"; 21 | 22 | public const string DeveloperTokenId = "urn:altinn:developertokenid"; 23 | 24 | public const string AuthenticationMethod = "urn:altinn:authenticationmethod"; 25 | 26 | public const string Org = "urn:altinn:org"; 27 | 28 | public const string OrgNumber = "urn:altinn:orgNumber"; 29 | } 30 | -------------------------------------------------------------------------------- /frontend/playwright/e2eTests/selectSystemVendor.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from '@playwright/test'; 2 | import { SystemUserPage } from '../pages/systemUserPage'; 3 | import { TestdataApi } from 'playwright/util/TestdataApi'; 4 | import { ApiRequests } from 'playwright/api-requests/ApiRequests'; 5 | 6 | 7 | test.describe('System Register', async () => { 8 | let system: string; 9 | 10 | test.beforeEach(async () => { 11 | const api = new ApiRequests(); 12 | system = await api.createSystemSystemRegister(); // Create system before each test 13 | }); 14 | 15 | test('Create system user and verify landing page', async ({ page }): Promise => { 16 | const systemUserPage = new SystemUserPage(page); 17 | await systemUserPage.selectSystem(system); 18 | await systemUserPage.CREATE_SYSTEM_USER_BUTTON.click(); 19 | await expect(systemUserPage.SYSTEMUSER_CREATED_HEADING).toBeVisible(); 20 | await expect(page.getByText(system).first()).toBeVisible(); 21 | }); 22 | 23 | test.afterEach(async () => { 24 | if (system) { 25 | await TestdataApi.removeSystem(system); 26 | } 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Altinn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Mocks/Mocks/UserProfiles/UserProfileClientMock.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Core.UserProfiles; 2 | using Altinn.Platform.Profile.Models; 3 | 4 | namespace Altinn.Authentication.UI.Mocks.UserProfiles; 5 | 6 | public class UserProfileClientMock : IUserProfileClient 7 | { 8 | public async Task GetUserProfile(int userid) 9 | { 10 | await Task.Delay(50); 11 | 12 | UserProfile user = new() 13 | { 14 | UserId = 7007, 15 | Email = "1337@altinnstudiotestusers.com", 16 | PhoneNumber = "90001337", 17 | UserName = "Testur Testursson Jr", 18 | PartyId = 50019992, 19 | ExternalIdentity = "", 20 | Party = new Platform.Register.Models.Party 21 | { 22 | Name = "Test Organisasjon" 23 | }, 24 | ProfileSettingPreference = new() 25 | { 26 | Language = "nb" 27 | }, 28 | UserType = Platform.Profile.Enums.UserType.SSNIdentified 29 | 30 | }; 31 | 32 | return user; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Tests/Health/HealthCheckTest.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authentication.UI.Health; 2 | using Altinn.Authentication.UI.Tests.Utils; 3 | using Microsoft.Extensions.Diagnostics.HealthChecks; 4 | using Newtonsoft.Json; 5 | using System.Net; 6 | using Xunit; 7 | 8 | namespace Altinn.Authentication.UI.Tests; 9 | 10 | public class HealthCheckTest :IClassFixture> 11 | { 12 | private readonly CustomWebApplicationFactory _factory; 13 | 14 | public HealthCheckTest(CustomWebApplicationFactory factory) 15 | { 16 | _factory = factory; 17 | } 18 | 19 | [Fact] 20 | public async Task VerifyHealthCheck_OK() 21 | { 22 | HttpClient client = SetupUtils.GetTestClient(_factory, false); 23 | HttpRequestMessage request = new(HttpMethod.Get, $"/health"); 24 | HttpResponseMessage response = await client.SendAsync(request); 25 | 26 | Assert.Equal(HttpStatusCode.OK, response.StatusCode); 27 | string result = await response.Content.ReadAsStringAsync(); 28 | Assert.Equal(HealthStatus.Healthy.ToString() ,result); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemUsers/SystemUserRequestDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemUsers; 4 | 5 | /// 6 | /// When the Frontend POST a new SystemUser this is the DTO 7 | /// sent to the Authentication Component 8 | /// 9 | public class SystemUserRequestDto 10 | { 11 | /// 12 | /// The Title is set by the end-user in the Frontend, by default it is the same as the System's Display Name 13 | /// Even if this DTO allows null, the db field is of course still required 14 | /// 15 | [JsonPropertyName("integrationTitle")] 16 | public string IntegrationTitle { get; set; } 17 | 18 | /// 19 | /// For off the shelf systems. 20 | /// Should probably be human readable (instead of a GUID) but unique string without whitespace 21 | /// The "real" Authentication Component should validate that the SystemName is unique 22 | /// Retrieved from the SystemRegister, the full CRUD Api is in a different service 23 | /// 24 | [JsonPropertyName("systemId")] 25 | public string SystemId { get; set; } 26 | } -------------------------------------------------------------------------------- /frontend/src/components/ActionBar/ActionBarHeader.module.css: -------------------------------------------------------------------------------- 1 | .actionBar { 2 | display: flex; 3 | border: 1px var(--border-color) solid; 4 | border-radius: 4px; 5 | background-color: var(--background-color); 6 | margin-top: var(--ds-size-2); 7 | } 8 | 9 | .actionBar.open { 10 | border-bottom-right-radius: 0px; 11 | border-bottom-left-radius: 0px; 12 | border-bottom-style: none; 13 | } 14 | 15 | .actionBar.light { 16 | --border-color: var(--ds-color-neutral-border-subtle); 17 | --background-color: #fff; 18 | } 19 | 20 | .actionBar.neutral { 21 | --border-color: var(--ds-color-neutral-border-subtle); 22 | --background-color: var(--ds-color-neutral-background-subtle); 23 | } 24 | 25 | .actionBarHeader { 26 | color: inherit; 27 | height: auto; 28 | width: 100%; 29 | } 30 | 31 | .title { 32 | font-weight: 500; 33 | } 34 | 35 | .actionBarButtonContainer { 36 | display: flex; 37 | gap: var(--ds-size-4); 38 | align-items: center; 39 | height: 100%; 40 | width: 100%; 41 | } 42 | 43 | .titleWrapper { 44 | flex: 1; 45 | display: flex; 46 | flex-direction: row; 47 | gap: var(--ds-size-4); 48 | height: 100%; 49 | position: relative; 50 | align-items: center; 51 | } 52 | -------------------------------------------------------------------------------- /frontend/src/components/RequestPage/RequestPage.module.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --vendor-container-padding: var(--ds-size-12); 3 | } 4 | 5 | @media only screen and (max-width: 769px) { 6 | :root { 7 | --vendor-container-padding: var(--ds-size-4); 8 | } 9 | } 10 | 11 | .requestPage { 12 | min-height: 100vh; 13 | background-color: #f3f4f4; 14 | } 15 | 16 | .requestWrapper { 17 | margin-left: auto; 18 | margin-right: auto; 19 | min-width: 280px; 20 | max-width: 1056px; 21 | } 22 | 23 | .headerContainer { 24 | display: flex; 25 | flex-direction: row; 26 | justify-content: space-between; 27 | align-items: center; 28 | text-align: right; 29 | font-size: 16px; 30 | padding: var(--vendor-container-padding); 31 | } 32 | 33 | .vendorInfo { 34 | padding-top: var(--ds-size-4); 35 | padding-right: var(--vendor-container-padding); 36 | padding-bottom: var(--vendor-container-padding); 37 | text-align: right; 38 | font-style: italic; 39 | } 40 | 41 | .vendorRequestBlock { 42 | display: flex; 43 | flex-direction: column; 44 | gap: var(--ds-size-8); 45 | background-color: var(--ds-color-accent-background-default); 46 | padding: var(--vendor-container-padding); 47 | margin-bottom: 3px; 48 | } 49 | -------------------------------------------------------------------------------- /.github/workflows/build-frontend-on-pr.yml: -------------------------------------------------------------------------------- 1 | name: Build and lint frontend 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [main] 7 | paths-ignore: 8 | - bff/** 9 | 10 | pull_request: 11 | types: [opened, synchronize, reopened] 12 | paths-ignore: 13 | - bff/** 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | name: Test & Build 19 | steps: 20 | - name: checkout 21 | uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 22 | with: 23 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 24 | 25 | - name: Enable Corepack to use yarn version > 1 26 | run: corepack enable 27 | 28 | - name: install dependencies 29 | working-directory: ./frontend 30 | run: yarn --immutable 31 | 32 | - name: install node 33 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 34 | with: 35 | node-version: lts/* 36 | 37 | - name: run eslint 38 | working-directory: ./frontend 39 | run: yarn lint 40 | 41 | - name: run build 42 | working-directory: ./frontend 43 | run: yarn build 44 | -------------------------------------------------------------------------------- /frontend/src/routes/Router/Router.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createBrowserRouter, createRoutesFromElements, Route } from 'react-router-dom'; 3 | 4 | const getNewUiUrl = (): string => { 5 | const host = window.location.hostname.replace('authn.ui.', 'am.ui.'); 6 | return `https://${host}/accessmanagement/ui/systemuser/overview`; 7 | }; 8 | 9 | const NewPageAlert = () => { 10 | return ( 11 | 19 | 27 | Systemtilgang-sidene er flyttet til en ny url, vennligst gå til{' '} 28 | 29 | {getNewUiUrl()} 30 | 31 | 32 | 33 | ); 34 | }; 35 | 36 | export const Router = createBrowserRouter( 37 | createRoutesFromElements(}>), 38 | { basename: '/authfront/ui' }, 39 | ); 40 | -------------------------------------------------------------------------------- /frontend/src/assets/Settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/components/UserInfoBar/UserInfoBar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Buildings3FillIcon } from '@navikt/aksel-icons'; 3 | import AltinnLogo from '@/assets/AltinnTextLogo.svg?react'; 4 | import classes from './UserInfoBar.module.css'; 5 | import { useGetLoggedInUserQuery } from '@/rtk/features/userApi'; 6 | 7 | export const UserInfoBar = () => { 8 | const { data: userInfo } = useGetLoggedInUserQuery(); 9 | 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {userInfo?.loggedInPersonName && ( 19 | {userInfo.loggedInPersonName} 20 | )} 21 | {userInfo?.representingPartyName && ( 22 | 23 | {userInfo?.loggedInPersonName && 'for '} 24 | {userInfo.representingPartyName} 25 | 26 | )} 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | }; 34 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Tests/platform-org.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDAzCCAeugAwIBAgIJANTdO8o3I8x5MA0GCSqGSIb3DQEBCwUAMA4xDDAKBgNV 3 | BAMTA3R0ZDAeFw0yMDA1MjUxMjIxMzdaFw0zMDA1MjQxMjIxMzdaMA4xDDAKBgNV 4 | BAMTA3R0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcfTsXwwLyC 5 | UkIz06eadWJvG3yrzT+ZB2Oy/WPaZosDnPcnZvCDueN+oy0zTx5TyH5gCi1FvzX2 6 | 7G2eZEKwQaRPv0yuM+McHy1rXxMSOlH/ebP9KJj3FDMUgZl1DCAjJxSAANdTwdrq 7 | ydVg1Crp37AQx8IIEjnBhXsfQh1uPGt1XwgeNyjl00IejxvQOPzd1CofYWwODVtQ 8 | l3PKn1SEgOGcB6wuHNRlnZPCIelQmqxWkcEZiu/NU+kst3NspVUQG2Jf2AF8UWgC 9 | rnrhMQR0Ra1Vi7bWpu6QIKYkN9q0NRHeRSsELOvTh1FgDySYJtNd2xDRSf6IvOiu 10 | tSipl1NZlV0CAwEAAaNkMGIwIAYDVR0OAQH/BBYEFIwq/KbSMzLETdo9NNxj0rz4 11 | qMqVMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMCAGA1UdJQEB/wQWMBQG 12 | CCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAE56UmH5gEYbe 13 | 1kVw7nrfH0R9FyVZGeQQWBn4/6Ifn+eMS9mxqe0Lq74Ue1zEzvRhRRqWYi9JlKNf 14 | 7QQNrc+DzCceIa1U6cMXgXKuXquVHLmRfqvKHbWHJfIkaY8Mlfy++77UmbkvIzly 15 | T1HVhKKp6Xx0r5koa6frBh4Xo/vKBlEyQxWLWF0RPGpGErnYIosJ41M3Po3nw3lY 16 | f7lmH47cdXatcntj2Ho/b2wGi9+W29teVCDfHn2/0oqc7K0EOY9c2ODLjUvQyPZR 17 | OD2yykpyh9x/YeYHFDYdLDJ76/kIdxN43kLU4/hTrh9tMb1PZF+/4DshpAlRoQuL 18 | o8I8avQm/A== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/Common/Problems/ProblemMapper.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authorization.ProblemDetails; 2 | 3 | namespace Altinn.Authentication.UI.Core.Common.Problems; 4 | /// 5 | /// Problem descriptors for the Authentication UI BFF. 6 | /// 7 | public static class ProblemMapper 8 | { 9 | public static ProblemDescriptor MapToAuthUiError(string? authErrorCode) 10 | { 11 | return authErrorCode switch 12 | { 13 | "AUTH-00001" => Problem.Rights_NotFound_Or_NotDelegable, 14 | "AUTH-00002" => Problem.Rights_FailedToDelegate, 15 | "AUTH-00003" => Problem.SystemUser_FailedToCreate, 16 | "AUTH-00004" => Problem.SystemUser_AlreadyExists, 17 | "AUTH-00011" => Problem.SystemIdNotFound, 18 | "AUTH-00014" => Problem.UnableToDoDelegationCheck, 19 | "AUTH-00016" => Problem.DelegationRightMissingRoleAccess, 20 | "AUTH-00018" => Problem.DelegationRightMissingDelegationAccess, 21 | "AUTH-00019" => Problem.DelegationRightMissingSrrRightAccess, 22 | "AUTH-00020" => Problem.DelegationRightInsufficientAuthenticationLevel, 23 | _ => Problem.Generic_EndOfMethod, 24 | }; 25 | } 26 | } -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "PlatformSettings": { 3 | "ApiAccessManagementEndpoint": "http://localhost:5117/accessmanagement/api/v1/", 4 | "ApiAuthenticationEndpoint": "https://localhost:44377/authentication/api/v1/", 5 | "ApiProfileEndpoint": "http://localhost:5101/profile/api/v1/", 6 | "JwtCookieName": "AltinnStudioRuntime", 7 | "OpenIdWellKnownEndpoint": "http://localhost:5101/authentication/api/v1/", 8 | "SubscriptionKeyHeaderName": "Ocp-Apim-Subscription-Key", 9 | "ApiRegisterEndpoint": "https://platform.at22.altinn.cloud/register/api/v1/", 10 | "ResourceRegistryEndpoint": "https://platform.at22.altinn.cloud/resourceregistry/api/v1/" 11 | }, 12 | "CacheConfig": { 13 | "PartyCacheTimeout": 10, 14 | "ResourceRegistryResourceCacheTimeout": 10, 15 | "ResourceOwnerCacheTimeout": 10 16 | }, 17 | "GeneralSettings": { 18 | "FrontendBaseUrl": "http://localhost:5101", 19 | "Hostname": "localhost", 20 | "LanguageCookie": "i18next", 21 | "UseMockData": false 22 | }, 23 | "KeyVaultSettings": { 24 | "SecretUri": "" 25 | }, 26 | "ClientSettings": { 27 | "Issuer": "authnui", 28 | "App": "authentication-ui", 29 | "CertificateName": "JWTCertificate" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/SystemUsers/ISystemUserService.cs: -------------------------------------------------------------------------------- 1 | using Altinn.Authorization.ProblemDetails; 2 | 3 | namespace Altinn.Authentication.UI.Core.SystemUsers; 4 | 5 | /// 6 | /// The "middleware" between the BFF's SystemUserAPI and Altinn's real SystemUserAPI in the Authentication Component 7 | /// 8 | public interface ISystemUserService 9 | { 10 | /// 11 | /// Return all system users created for a given party 12 | /// 13 | Task>> GetAllSystemUsersForParty(int partyId, CancellationToken cancellationToken = default); 14 | Task GetSpecificSystemUserDTO(int partyId, Guid id, CancellationToken cancellationToken = default); 15 | 16 | Task> CreateSystemUser(int partyId, SystemUserRequestDto newSystemUserDescriptor, CancellationToken cancellation = default); 17 | 18 | /// 19 | /// Deletes system user 20 | /// 21 | Task> DeleteSystemUser(int partyId, Guid id, CancellationToken cancellationToken = default); 22 | 23 | /// 24 | /// Change system user title 25 | /// 26 | Task ChangeSystemUserTitle(string newTitle, Guid id, CancellationToken cancellationToken = default); 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/assets/Api.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/features/detailpage/DetailPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useParams } from 'react-router-dom'; 3 | import { useTranslation } from 'react-i18next'; 4 | import { Alert, Spinner } from '@digdir/designsystemet-react'; 5 | import { Page, PageContainer } from '@/components'; 6 | import { DetailPageContent } from './DetailPageContent'; 7 | import ApiIcon from '@/assets/Api.svg?react'; 8 | import { useGetSystemUserQuery } from '@/rtk/features/systemUserApi'; 9 | import { AuthenticationRoute } from '@/routes/paths'; 10 | 11 | export const DetailPage = (): React.ReactNode => { 12 | const { t } = useTranslation(); 13 | const { id } = useParams(); 14 | 15 | const { 16 | data: systemUser, 17 | isError: isLoadSystemUserError, 18 | isLoading: isLoadingSystemUser, 19 | } = useGetSystemUserQuery(id || ''); 20 | 21 | return ( 22 | 23 | } title={t('authent_detailpage.edit_systemuser')}> 24 | {isLoadingSystemUser && } 25 | {isLoadSystemUserError && ( 26 | {t('authent_detailpage.load_systemuser_error')} 27 | )} 28 | {systemUser && } 29 | 30 | 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Middleware/SecurityHeadersMiddleware.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Altinn.Authentication.UI.Middleware; 3 | 4 | /// 5 | /// Middleware for sending security headers in response. 6 | /// 7 | /// The following headers will be set: 8 | /// X-Frame-Options 9 | /// X-Content-Type-Options 10 | /// X-XSS-Protection 11 | /// Referer-Policy 12 | /// 13 | public class SecurityHeadersMiddleware 14 | { 15 | private readonly RequestDelegate _next; 16 | 17 | /// 18 | /// Default constructor for ASPNET Core Middleware. 19 | /// 20 | /// The next middleware 21 | public SecurityHeadersMiddleware(RequestDelegate next) 22 | { 23 | _next = next; 24 | } 25 | 26 | /// 27 | /// Executes the middleware. Expects the next middleware to be executed. 28 | /// 29 | /// The current HttpContext 30 | /// 31 | public Task Invoke(HttpContext context) 32 | { 33 | context.Response.Headers.Add("X-Frame-Options", "deny"); 34 | context.Response.Headers.Add("X-Content-Type-Options", "nosniff"); 35 | context.Response.Headers.Add("X-XSS-Protection", "0"); 36 | context.Response.Headers.Add("Referer-Policy", "no-referer"); 37 | 38 | return _next(context); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /frontend/eslint.config.js: -------------------------------------------------------------------------------- 1 | import eslint from '@eslint/js'; 2 | import tseslint from 'typescript-eslint'; 3 | import reactRecommended from 'eslint-plugin-react/configs/recommended.js'; 4 | import eslintPluginReactHooks from 'eslint-plugin-react-hooks'; 5 | 6 | export default tseslint.config( 7 | eslint.configs.recommended, 8 | ...tseslint.configs.recommended, 9 | ...tseslint.configs.stylistic, 10 | reactRecommended, 11 | { 12 | settings: { 13 | react: { 14 | version: 'detect', 15 | }, 16 | }, 17 | }, 18 | { 19 | files: ['src/**.ts*'], 20 | }, 21 | { 22 | ignores: ['dist/**', 'vite.config.ts', 'config.ts'], 23 | }, 24 | { 25 | plugins: { 26 | 'react-hooks': eslintPluginReactHooks, 27 | }, 28 | }, 29 | { 30 | languageOptions: { 31 | parserOptions: { ecmaFeatures: { jsx: true } }, 32 | }, 33 | }, 34 | { 35 | rules: { 36 | ...eslintPluginReactHooks.configs.recommended.rules, 37 | 'react/jsx-filename-extension': ['warn', { extensions: ['.tsx', '.jsx'] }], 38 | 'prefer-const': 'error', 39 | 'object-curly-spacing': ['error', 'always'], 40 | 'no-duplicate-imports': 'error', 41 | eqeqeq: 'error', 42 | '@typescript-eslint/no-use-before-define': 'off', 43 | '@typescript-eslint/no-explicit-any': 'error', 44 | '@typescript-eslint/no-unused-vars': 'warn', 45 | }, 46 | }, 47 | ); 48 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Mocks/Mocks/HomeAndAuth/JwtCookiePostConfigureOptions.cs: -------------------------------------------------------------------------------- 1 | using AltinnCore.Authentication.JwtCookie; 2 | using Microsoft.AspNetCore.Authentication.Cookies; 3 | using Microsoft.Extensions.Options; 4 | 5 | namespace Altinn.Authentication.UI.Mocks.Mocks; 6 | 7 | /// 8 | /// Represents a stub for the class to be used in integration tests. 9 | /// 10 | public class JwtCookiePostConfigureOptionsStub : IPostConfigureOptions 11 | { 12 | /// 13 | public void PostConfigure(string? name, JwtCookieOptions options) 14 | { 15 | if (string.IsNullOrEmpty(options.JwtCookieName)) 16 | { 17 | options.JwtCookieName = JwtCookieDefaults.CookiePrefix + name; 18 | } 19 | 20 | if (options.CookieManager == null) 21 | { 22 | options.CookieManager = new ChunkingCookieManager(); 23 | } 24 | 25 | if (!string.IsNullOrEmpty(options.MetadataAddress)) 26 | { 27 | if (!options.MetadataAddress.EndsWith("/", StringComparison.Ordinal)) 28 | { 29 | options.MetadataAddress += "/"; 30 | } 31 | } 32 | 33 | options.MetadataAddress += ".well-known/openid-configuration"; 34 | options.ConfigurationManager = new ConfigurationManagerStub(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Core/Authentication/AuthenticationHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System.Security.Claims; 3 | 4 | namespace Altinn.Authentication.UI.Core.Authentication; 5 | 6 | public static class AuthenticationHelper 7 | { 8 | 9 | public static int GetUserId(HttpContext context) => 10 | GetIntValueFromClaim(context, AltinnCoreClaimType.UserId); 11 | 12 | public static int GetUserAuthenticationLevel(HttpContext context) => 13 | GetIntValueFromClaim(context, AltinnCoreClaimType.AuthenticationLevel); 14 | 15 | public static int GetUsersPartyId(HttpContext context) => 16 | GetIntValueFromClaim(context, AltinnCoreClaimType.PartyId); 17 | 18 | public static int GetRepresentingPartyId(HttpContext context) 19 | { 20 | return Convert.ToInt32(context.Request.Cookies["AltinnPartyId"]); 21 | } 22 | 23 | private static int GetIntValueFromClaim(HttpContext context, string claimType) 24 | { 25 | int value = 0; 26 | 27 | if (context.User is not null) 28 | { 29 | foreach (Claim claim in context.User.Claims) 30 | { 31 | if (claim.Type.ToString().Equals(claimType)) 32 | { 33 | value = Convert.ToInt32(claim.Value); 34 | return value; 35 | } 36 | } 37 | } 38 | return value; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #Building the Authentication Frontend 2 | FROM node:alpine@sha256:7e467cc5aa91c87e94f93c4608cf234ca24aac3ec941f7f3db207367ccccdd11 AS generate-authentication-frontend 3 | WORKDIR /build 4 | COPY frontend . 5 | RUN corepack enable 6 | RUN yarn --immutable 7 | RUN yarn build 8 | 9 | #Building the Authentication BFF Backend 10 | 11 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine@sha256:512f8347b0d2f9848f099a8c31be07286955ceea337cadb1114057ed0b15862f AS generate-authentication-backend 12 | 13 | COPY bff/src . 14 | RUN dotnet publish Altinn.Authentication.UI/Altinn.Authentication.UI/Altinn.Authentication.UI.csproj -c Release -r linux-x64 -o /app_output --no-self-contained 15 | 16 | #Building the final image 17 | 18 | FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine@sha256:07c48612ac44393b15e741734761cf1f30cdb8f7e645e66e25b4563681ceef99 AS final 19 | 20 | EXPOSE 8080/tcp 21 | #EXPOSE 443 22 | WORKDIR /app 23 | #ENV ASPNETCORE_ENVIRONMENT=Development 24 | RUN apk add --no-cache icu-libs krb5-libs libgcc libintl libssl3 libstdc++ zlib 25 | 26 | COPY --from=generate-authentication-backend /app_output . 27 | COPY --from=generate-authentication-frontend /build/dist/assets ./wwwroot/authentication/assets 28 | COPY --from=generate-authentication-frontend /build/src/localizations ./wwwroot/authentication/localizations 29 | COPY --from=generate-authentication-frontend /build/dist/manifest.json ./wwwroot/authentication 30 | 31 | RUN mkdir /tmp/logtelemetry 32 | ENTRYPOINT ["dotnet", "Altinn.Authentication.UI.dll"] 33 | 34 | -------------------------------------------------------------------------------- /.github/actions/deploy/action.yml: -------------------------------------------------------------------------------- 1 | name: "Deploy authentication-ui to environment" 2 | description: "Deploy authentication-ui to a given environment" 3 | inputs: 4 | image-name: 5 | description: "The name of the image to deploy" 6 | required: false 7 | type: string 8 | default: ghcr.io/altinn/altinn-authentication-frontend 9 | image-tag: 10 | description: "The tag of the image to deploy" 11 | required: true 12 | type: string 13 | container-name: 14 | description: "The name of the container in the containerapp" 15 | required: false 16 | type: string 17 | default: authentication-frontend 18 | resource-group: 19 | description: "The name of the resource group in Azure" 20 | required: true 21 | type: string 22 | container-app: 23 | description: "The name of the containerapp in Azure" 24 | required: true 25 | type: string 26 | 27 | runs: 28 | using: "composite" 29 | steps: 30 | - uses: denoland/setup-deno@v1 31 | with: 32 | deno-version: v1.x 33 | 34 | - name: Test 35 | run: az account show 36 | shell: bash 37 | 38 | - name: Deploy Image to ContainerApp 39 | shell: bash 40 | env: 41 | NAME: ${{ inputs.container-app }} 42 | CONTAINER_NAME: ${{ inputs.container-name }} 43 | RESOURCE_GROUP: ${{ inputs.resource-group }} 44 | IMAGE: ${{ inputs.image-name }}:${{ inputs.image-tag }} 45 | FORCE_COLOR: '2' 46 | run: deno run -A ./.github/actions/deploy/deploy.mts 47 | -------------------------------------------------------------------------------- /frontend/src/components/RightsList/RightsList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTranslation } from 'react-i18next'; 3 | import { ServiceResource } from '@/types'; 4 | import { ActionBar } from '../ActionBar'; 5 | import { i18nLanguageToShortLanguageCode } from '@/utils/languageUtils'; 6 | import { RightsListLogo } from './RightsListLogo'; 7 | 8 | interface RightsListProps { 9 | resources: ServiceResource[]; 10 | } 11 | 12 | export const RightsList = ({ resources }: RightsListProps): React.ReactNode => { 13 | const { i18n } = useTranslation(); 14 | const currentLanguage = i18nLanguageToShortLanguageCode(i18n.language); 15 | return ( 16 | 17 | {resources.map((resource) => { 18 | return ( 19 | 20 | 28 | ) 29 | } 30 | subtitle={resource?.hasCompetentAuthority?.name?.[currentLanguage]} 31 | color='neutral' 32 | > 33 | {resource.description?.[currentLanguage]} 34 | 35 | 36 | ); 37 | })} 38 | 39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Extensions/DataProtectionConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.DataProtection.Repositories; 2 | using Microsoft.AspNetCore.DataProtection; 3 | 4 | namespace Altinn.Authentication.UI.Extensions; 5 | 6 | 7 | /// 8 | /// Configuration for DataProtection 9 | /// 10 | public static class DataProtectionConfiguration 11 | { 12 | /// 13 | /// Configure data protection on the services collection. 14 | /// 15 | /// The service collections 16 | public static void ConfigureDataProtection(this IServiceCollection services) 17 | { 18 | services 19 | .AddDataProtection() 20 | .PersistKeysToFileSystem(GetKeysDirectory()); 21 | } 22 | 23 | /// 24 | /// Return a directory based on the running operating system. It is possible to override the directory based on the ALTINN_KEYS_DIRECTORY environment variable. 25 | /// 26 | /// 27 | private static DirectoryInfo GetKeysDirectory() 28 | { 29 | var environmentVariable = System.Environment.GetEnvironmentVariable("ALTINN_KEYS_DIRECTORY"); 30 | if (!string.IsNullOrWhiteSpace(environmentVariable)) 31 | { 32 | return new DirectoryInfo(environmentVariable); 33 | } 34 | 35 | // Return a key directory based on the current operating system 36 | return FileSystemXmlRepository.DefaultKeyStorageDirectory!; 37 | } 38 | } -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Health/HealthTelemetryFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using Microsoft.ApplicationInsights.Channel; 3 | using Microsoft.ApplicationInsights.DataContracts; 4 | using Microsoft.ApplicationInsights.Extensibility; 5 | 6 | namespace Altinn.Authentication.UI.Health 7 | { 8 | /// 9 | /// Filter to exclude health check request from Application Insights 10 | /// 11 | [ExcludeFromCodeCoverage] 12 | public class HealthTelemetryFilter : ITelemetryProcessor 13 | { 14 | private ITelemetryProcessor Next { get; set; } 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | public HealthTelemetryFilter(ITelemetryProcessor next) 20 | { 21 | Next = next; 22 | } 23 | 24 | /// 25 | public void Process(ITelemetry item) 26 | { 27 | if (ExcludeItemTelemetry(item)) 28 | { 29 | return; 30 | } 31 | 32 | Next.Process(item); 33 | } 34 | 35 | private bool ExcludeItemTelemetry(ITelemetry item) 36 | { 37 | RequestTelemetry request = item as RequestTelemetry; 38 | 39 | if (request != null && request.Url.ToString().EndsWith("/health/")) 40 | { 41 | return true; 42 | } 43 | 44 | return false; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "swagger", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Development" 9 | }, 10 | "dotnetRunMessages": true, 11 | "applicationUrl": "http://localhost:5006" 12 | }, 13 | "https": { 14 | "commandName": "Project", 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | }, 20 | "dotnetRunMessages": true, 21 | "applicationUrl": "https://localhost:7079;http://localhost:5110" 22 | }, 23 | "IIS Express": { 24 | "commandName": "IISExpress", 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "environmentVariables": { 28 | "ASPNETCORE_ENVIRONMENT": "Development" 29 | } 30 | }, 31 | "Docker": { 32 | "commandName": "Docker", 33 | "launchBrowser": true, 34 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", 35 | "publishAllPorts": true, 36 | "useSSL": true 37 | } 38 | }, 39 | "$schema": "https://json.schemastore.org/launchsettings.json", 40 | "iisSettings": { 41 | "windowsAuthentication": false, 42 | "anonymousAuthentication": true, 43 | "iisExpress": { 44 | "applicationUrl": "http://localhost:5005", 45 | "sslPort": 44329 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /bff/src/Altinn.Authentication.UI/Altinn.Authentication.UI.Tests/selfSignedTestCertificatePublic.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID/zCCAuegAwIBAgIQF2ov3ZZUmJVKtoz0a1fabDANBgkqhkiG9w0BAQsFADB/ 3 | MRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHY29udG9zbzEU 4 | MBIGCgmSJomT8ixkARkWBGNvcnAxFTATBgNVBAsMDFVzZXJBY2NvdW50czEiMCAG 5 | A1UEAwwZQWx0aW5uIFBsYXRmb3JtIFVuaXQgdGVzdDAgFw0yMDA0MTQwOTMwMTda 6 | GA8yMTIwMDQxNDA5NDAxOFowfzETMBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmS 7 | JomT8ixkARkWB2NvbnRvc28xFDASBgoJkiaJk/IsZAEZFgRjb3JwMRUwEwYDVQQL 8 | DAxVc2VyQWNjb3VudHMxIjAgBgNVBAMMGUFsdGlubiBQbGF0Zm9ybSBVbml0IHRl 9 | c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCAKc+q5jbYFyQFxM1 10 | xU3v0N477ppnMu03K8qlEkX0+yffRHcR1I0Kku8yg1S+LQjeqh1K42b270myKiIt 11 | vxeuNnanRwdehTZthThembr8RXoGcmzaXfMet7NVDgUa7gNzPXbqjhTFdyWoZzeU 12 | X6TWTgFtciTs5M1F50H+3nieGKX2dvLUIEXWFO7yevj9bqtI8k0b66eLgBjchnjW 13 | 8B7oYOFZW44VDDnqQrvFJ9aMQ44FfLAWWLcy6nBzcDdK+Z+yq9FNVgduyl0J7vRo 14 | 3UtcVazLUvmDdwASLIB3IwB7YmT6fuOyM+6eyw5F1CdjXbc/bhop0pCDY1aAEsZA 15 | CjT9AgMBAAGjdTBzMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD 16 | AjAtBgNVHREEJjAkoCIGCisGAQQBgjcUAgOgFAwSdGVzdEBhbHRpbm4uc3R1ZGlv 17 | MB0GA1UdDgQWBBTv8Cpf5J7nfmGds20LU/J3bg05XTANBgkqhkiG9w0BAQsFAAOC 18 | AQEAahWeu6ymaiJe9+LiMlQwNsUIV4KaLX+jCsRyF1jUJ0C13aFALGM4k9svqqXR 19 | DzBdCXXr0c1E+Ks3sCwBLfK5yj5fTI+pL26ceEmHahcVyLvzEBljtNb4FnGFs92P 20 | CH0NuCz45hQ2O9/Tv4cZAdgledTznJTKzzQNaF8M6iINmP6sf4kOg0BQx0K71K4f 21 | 7j2oQvYKiT7Zv1e83cdk9pS4ihDe+ZWYiGUM/IuaXNPl6OzVk4rY88PZJAoz7q33 22 | rYjlT+zkcl3dzTc3E0CWzbIWjhaXCRWvlI44cLRtdpmPqJUHI6a/tcGwNb5vWiT4 23 | YfZJ0EZ2iSRQlpU3+jMs8Ci2AA== 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /frontend/playwright/e2eTests/deleteSystemUser.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from '@playwright/test'; 2 | import { SystemUserPage } from '../pages/systemUserPage'; 3 | import { ApiRequests } from 'playwright/api-requests/ApiRequests'; 4 | import { TestdataApi } from 'playwright/util/TestdataApi'; 5 | 6 | test.describe('System user deletion', () => { 7 | let systemId: string; 8 | let api: ApiRequests; 9 | 10 | test.beforeAll(async () => { 11 | api = new ApiRequests(); 12 | }); 13 | 14 | test.beforeEach(async ({ page }) => { 15 | //Create a system in your "system register" before each test 16 | systemId = await api.createSystemSystemRegister(); 17 | 18 | // 2) Use the UI to create a new system user 19 | const systemUserPage = new SystemUserPage(page); 20 | await systemUserPage.selectSystem(systemId); 21 | await systemUserPage.CREATE_SYSTEM_USER_BUTTON.click(); 22 | await expect(systemUserPage.SYSTEMUSER_CREATED_HEADING).toBeVisible(); 23 | await expect(page.getByText(systemId).first()).toBeVisible(); 24 | }); 25 | 26 | test('Delete created system user', async ({ page }) => { 27 | const systemUserPage = new SystemUserPage(page); 28 | 29 | // Delete system user 30 | await systemUserPage.EDIT_SYSTEMUSER_LINK.click(); 31 | await systemUserPage.DELETE_SYSTEMUSER_BUTTON.click(); 32 | await systemUserPage.FINAL_DELETE_SYSTEMUSER_BUTTON.click(); 33 | 34 | // Confirm we are back on overview page 35 | await expect(systemUserPage.MAIN_HEADER).toBeVisible(); 36 | }); 37 | 38 | test.afterEach(async () => { 39 | // Remove system 40 | await TestdataApi.removeSystem(systemId); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /frontend/playwright/pages/loginPage.ts: -------------------------------------------------------------------------------- 1 | import { Locator, type Page, expect } from '@playwright/test'; 2 | 3 | const authFile = '.playwright/.auth/user.json'; 4 | 5 | export class LoginWithUserPage { 6 | public readonly LOGIN_BUTTON: Locator; 7 | 8 | constructor(public page: Page) { 9 | this.LOGIN_BUTTON = page.locator('span', { hasText: 'Logg inn/Min profil' }); 10 | } 11 | 12 | async loginAndChooseReportee(testUser: string, reportee: string) { 13 | await this.page.goto(`${process.env.BASE_URL}`); 14 | await this.page.click("'Logg inn/Min profil'"); 15 | await this.page.getByText('TestID Lag din egen').click(); 16 | await this.page.locator("input[name='pid']").fill(testUser); 17 | await this.page.click("'Autentiser'"); 18 | await this.page.getByRole('searchbox', { name: 'Søk etter aktør' }).fill(reportee); 19 | const chosenReportee = this.page.getByRole('button').filter({ hasText: reportee }); 20 | await chosenReportee.click(); 21 | await this.page.goto(`${process.env.BASE_URL}/ui/profile`); 22 | await this.page.click("'profil'"); 23 | const profileHeader = this.page.getByRole('heading', { name: new RegExp(reportee, 'i') }); 24 | await expect(profileHeader).toBeVisible(); 25 | await this.page.context().storageState({ path: authFile }); 26 | } 27 | } 28 | export class LogoutWithUserPage { 29 | constructor(public page: Page) {} 30 | 31 | async gotoLogoutPage(logoutReportee: string) { 32 | await this.page.goto(`${process.env.BASE_URL}/ui/profile`); 33 | await this.page.getByRole('button', { name: logoutReportee }).click(); 34 | await this.page.getByRole('link', { name: 'Logg ut' }).click(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "authentication-frontend", 3 | "private": true, 4 | "version": "0.0.1", 5 | "type": "module", 6 | "scripts": { 7 | "start": "vite", 8 | "build": "vite build", 9 | "lint": "eslint ." 10 | }, 11 | "dependencies": { 12 | "@digdir/designsystemet-css": "1.6.1", 13 | "@digdir/designsystemet-react": "1.6.1", 14 | "@digdir/designsystemet-theme": "1.6.1", 15 | "@navikt/aksel-icons": "^7.0.0", 16 | "@reduxjs/toolkit": "^2.1.0", 17 | "classnames": "^2.5.1", 18 | "i18next": "^25.0.0", 19 | "i18next-browser-languagedetector": "^8.0.0", 20 | "react": "^19.0.0", 21 | "react-dom": "^19.0.0", 22 | "react-i18next": "^15.0.0", 23 | "react-redux": "^9.1.0", 24 | "react-router-dom": "^7.0.0", 25 | "redux-logger": "^3.0.6" 26 | }, 27 | "devDependencies": { 28 | "@playwright/test": "^1.45.1", 29 | "@types/node": "^22.0.0", 30 | "@types/react": "^19.0.0", 31 | "@types/react-dom": "^19.0.0", 32 | "@types/redux-logger": "^3.0.13", 33 | "@vitejs/plugin-react": "^4.2.1", 34 | "eslint": "9.39.0", 35 | "eslint-plugin-react": "7.37.5", 36 | "eslint-plugin-react-hooks": "5.2.0", 37 | "husky": "^9.0.11", 38 | "lint-staged": "^15.2.2", 39 | "msw": "^2.4.11", 40 | "prettier": "^3.2.5", 41 | "typescript": "*", 42 | "typescript-eslint": "^8.0.0", 43 | "typescript-plugin-css-modules": "^5.1.0", 44 | "vite": "^6.0.0", 45 | "vite-plugin-svgr": "^4.2.0" 46 | }, 47 | "workspaces": [ 48 | "playwright" 49 | ], 50 | "packageManager": "yarn@4.10.3", 51 | "msw": { 52 | "workerDirectory": [ 53 | "" 54 | ] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /frontend/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Application configuration is obtained from three possible sources: 3 | * - fallback configuration (inline in this file) 4 | * - a JSON config object in a ` 34 | 35 | 36 | } 37 | else 38 | { 39 | 40 | 41 | } 42 |