diff --git a/c4po.sh b/c4po.sh index 37e44c0..a1fc8ea 100755 --- a/c4po.sh +++ b/c4po.sh @@ -14,14 +14,18 @@ ______| |______ |_____ |_____| | \_ __|__ | | _/_/_/ _/ echo "-------------CLEAN UP Container---------------" echo -e "\n" -docker rm -f c4po-keycloak -#docker rm -f c4po-db ### toggle to clear database with every start ### +#docker rm -f c4po-keycloak ### toggle to clear keycloak with every start ### +#docker rm -f c4po-db ### toggle to clear database with every start ### +docker rm -f c4po-reporting docker rm -f c4po-api docker rm -f c4po-angular echo -e "\n" echo "-----------------Start Build------------------" echo -e "\n" +echo " - Report Engine: " +docker-compose -f ${compose} build c4po-reporting +echo -e "\n" echo " - Backend: " docker-compose -f ${compose} build c4po-api echo -e "\n" diff --git a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.ts b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.ts index d1e4a15..995d31e 100644 --- a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.ts +++ b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.ts @@ -107,11 +107,11 @@ export class PentestHeaderComponent implements OnInit, OnDestroy { next: (pentest: Pentest) => { this.store.dispatch(new ChangePentest(pentest)); this.initialTimeSpent = pentest.timeSpent; - this.notificationService.showPopup('pentest.popup.complete.success', PopupType.SUCCESS); + this.notificationService.showPopup('pentest.popup.update.success', PopupType.SUCCESS); }, error: err => { console.log(err); - this.notificationService.showPopup('pentest.popup.complete.failed', PopupType.FAILURE); + this.notificationService.showPopup('pentest.popup.update.failed', PopupType.FAILURE); } }); } diff --git a/security-c4po-angular/src/shared/services/user-service/user.service.ts b/security-c4po-angular/src/shared/services/user-service/user.service.ts index 2722c7b..4b8d4f0 100644 --- a/security-c4po-angular/src/shared/services/user-service/user.service.ts +++ b/security-c4po-angular/src/shared/services/user-service/user.service.ts @@ -73,7 +73,7 @@ export class UserService { public redirectToChangePasswordAction(): Promise { // https://keycloak.discourse.group/t/integrate-change-password-from-account-console-into-own-webapp/12300 return this.keycloakService.login({ - action: 'UPDATE_PASSWORD', + action: 'UPDATE_PASSWORD' }); } diff --git a/security-c4po-cfg/cfg/c4po_realm_export.json b/security-c4po-cfg/cfg/c4po_realm_export.json index d076986..19a11af 100644 --- a/security-c4po-cfg/cfg/c4po_realm_export.json +++ b/security-c4po-cfg/cfg/c4po_realm_export.json @@ -267,6 +267,7 @@ } ], "security-admin-console" : [ ], "admin-cli" : [ ], + "security-c4po-reporting" : [ ], "c4po_local" : [ { "id" : "e26a27e7-1648-491b-832a-8bf751d378bb", "name" : "user", @@ -381,7 +382,7 @@ "otpPolicyLookAheadWindow" : 1, "otpPolicyPeriod" : 30, "otpPolicyCodeReusable" : false, - "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppFreeOTPName" ], + "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName" ], "webAuthnPolicyRpEntityName" : "keycloak", "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], "webAuthnPolicyRpId" : "", @@ -815,6 +816,43 @@ "nodeReRegistrationTimeout" : -1, "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "a30ec2f6-8dfb-4bae-9b61-fd39d0861a5b", + "clientId" : "security-c4po-reporting", + "name" : "", + "description" : "", + "rootUrl" : "", + "adminUrl" : "", + "baseUrl" : "http://localhost:8444/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "http://localhost:8444/*" ], + "webOrigins" : [ "*" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : true, + "protocol" : "openid-connect", + "attributes" : { + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "true", + "post.logout.redirect.uris" : "*", + "oauth2.device.authorization.grant.enabled" : "false", + "display.on.consent.screen" : "false", + "backchannel.logout.revoke.offline.tokens" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] } ], "clientScopes" : [ { "id" : "4b171f57-736a-41b4-b67b-585bac1d8d24", @@ -1324,7 +1362,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "saml-user-property-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper" ] } }, { "id" : "cc2d0cd7-3d3f-4b0a-ad95-7118f36bf188", @@ -1356,7 +1394,7 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "saml-role-list-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-user-property-mapper" ] } }, { "id" : "92230e65-7480-44c3-af2d-72ddee758cbc", @@ -1412,7 +1450,7 @@ "supportedLocales" : [ "de", "en" ], "defaultLocale" : "en", "authenticationFlows" : [ { - "id" : "0296b89f-2d7b-4931-b4ce-72167e83d8b7", + "id" : "bb40c574-9008-47b8-bdce-950f92219366", "alias" : "Account verification options", "description" : "Method with which to verity the existing account", "providerId" : "basic-flow", @@ -1434,7 +1472,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "64a2976c-5625-41a2-97d7-b53e78cc3a92", + "id" : "52866cca-eea7-4e24-ae8a-3e9d3cc10240", "alias" : "Authentication Options", "description" : "Authentication options.", "providerId" : "basic-flow", @@ -1463,7 +1501,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "23dce318-8864-429d-8e42-8f60adf87bb8", + "id" : "04f6c37f-e60c-41a4-a8f1-b09e3c3c791f", "alias" : "Browser - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -1485,7 +1523,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "07c663a3-9361-4fb1-ac6f-6af140b9d8b5", + "id" : "aac0d9a0-7ff3-4a3f-87f5-4a0f8dc4169c", "alias" : "Direct Grant - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -1507,7 +1545,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "8a797183-07fc-44a1-80a5-bfa6b4d727e1", + "id" : "a5103f9c-2ead-46d2-90dc-b93c8fad52de", "alias" : "First broker login - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -1529,7 +1567,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "98e3631a-0ff2-4528-b835-4836d755b430", + "id" : "7f2db66f-d81b-475a-aac0-860d2dff10b0", "alias" : "Handle Existing Account", "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", "providerId" : "basic-flow", @@ -1551,7 +1589,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "849a9f5a-0389-4de4-8da7-9561a1e266e8", + "id" : "5db5c83a-6ff7-41e7-97dd-dc896e7ed538", "alias" : "Reset - Conditional OTP", "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", "providerId" : "basic-flow", @@ -1573,7 +1611,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "e196e161-37ce-4616-be7f-b1742c4f7453", + "id" : "cea2f466-e748-4eec-8184-57620f9b6e19", "alias" : "User creation or linking", "description" : "Flow for the existing/non-existing user alternatives", "providerId" : "basic-flow", @@ -1596,7 +1634,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "ab6e417d-91a9-4a2e-a288-230b30ed2608", + "id" : "196ae0cd-faa3-45ed-9f94-5efabeda99b1", "alias" : "Verify Existing Account by Re-authentication", "description" : "Reauthentication of existing account", "providerId" : "basic-flow", @@ -1618,7 +1656,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "ed177a27-8acf-46c9-aecd-66a9de099b71", + "id" : "f26d09df-6c71-469f-a4d3-e97259b0d738", "alias" : "browser", "description" : "browser based authentication", "providerId" : "basic-flow", @@ -1654,7 +1692,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "7e14a81b-508b-4a78-aeca-c783e209209d", + "id" : "57839527-0e6b-491e-9509-64759543dc06", "alias" : "clients", "description" : "Base authentication for clients", "providerId" : "client-flow", @@ -1690,7 +1728,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "6e52e23e-d83f-46c2-bc4d-e336999e2293", + "id" : "4932ffe5-396c-4f34-a667-eda30f382396", "alias" : "direct grant", "description" : "OpenID Connect Resource Owner Grant", "providerId" : "basic-flow", @@ -1719,7 +1757,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "6d476080-ebc3-4bce-90ac-93afc891a83e", + "id" : "35410931-d63c-45fe-aa5c-b89b9ecbd803", "alias" : "docker auth", "description" : "Used by Docker clients to authenticate against the IDP", "providerId" : "basic-flow", @@ -1734,7 +1772,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "1143f6ea-867a-4b08-974e-86a4b9ba8601", + "id" : "40dbf210-48b5-4e51-bf2e-88eab2b7a9cb", "alias" : "first broker login", "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", "providerId" : "basic-flow", @@ -1757,7 +1795,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "2090f383-dcab-441c-9f37-5b37504a1692", + "id" : "9420c3e7-92b9-4332-a10c-9614041390a9", "alias" : "forms", "description" : "Username, password, otp and other auth forms.", "providerId" : "basic-flow", @@ -1779,7 +1817,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "13395ad8-a0eb-42f4-9d9d-c715c717d181", + "id" : "e87c0fc3-710d-447a-88de-966eb4b53178", "alias" : "http challenge", "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes", "providerId" : "basic-flow", @@ -1801,7 +1839,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "a656e7fc-fa52-46e3-9fc1-654cafe37087", + "id" : "b58bb0f2-c1aa-4a5a-9c18-f7f0b6951bb9", "alias" : "registration", "description" : "registration flow", "providerId" : "basic-flow", @@ -1817,7 +1855,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "84e1ffa9-3dd8-4b32-8cd9-e4bbc4631624", + "id" : "fa3cdbb3-9d7a-40a6-a76c-d8fc4de447db", "alias" : "registration form", "description" : "registration form", "providerId" : "form-flow", @@ -1853,7 +1891,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "68dad811-63ec-484a-a0b9-9656edc6921e", + "id" : "228942b7-863d-4ae7-8a03-f479e99563da", "alias" : "reset credentials", "description" : "Reset credentials for a user if they forgot their password or something", "providerId" : "basic-flow", @@ -1889,7 +1927,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "9a212f2d-80ae-4051-9d09-28d016809204", + "id" : "ea9b4826-ba5d-4753-be46-9aa3c4b9d543", "alias" : "saml ecp", "description" : "SAML ECP Profile Authentication Flow", "providerId" : "basic-flow", @@ -1905,13 +1943,13 @@ } ] } ], "authenticatorConfig" : [ { - "id" : "9e437782-7c8f-4732-a1e6-cd84abdf78e3", + "id" : "2f53b30a-881f-4407-8ffa-ea9540896bea", "alias" : "create unique user config", "config" : { "require.password.update.after.registration" : "false" } }, { - "id" : "8d01fb5d-be3d-42d9-ae27-592fab7d8d14", + "id" : "25c05d4a-ea77-4eb2-9fe4-93ebe228d10f", "alias" : "review profile config", "config" : { "update.profile.on.first.login" : "missing" diff --git a/security-c4po-cfg/cfg/old_c4po_realm_export.json b/security-c4po-cfg/cfg/old_c4po_realm_export.json index 6b62ef4..d076986 100644 --- a/security-c4po-cfg/cfg/old_c4po_realm_export.json +++ b/security-c4po-cfg/cfg/old_c4po_realm_export.json @@ -4,12 +4,13 @@ "displayName" : "C4PO", "displayNameHtml" : "
C4PO
", "notBefore" : 0, + "defaultSignatureAlgorithm" : "RS256", "revokeRefreshToken" : false, "refreshTokenMaxReuse" : 0, - "accessTokenLifespan" : 300, + "accessTokenLifespan" : 18000, "accessTokenLifespanForImplicitFlow" : 900, - "ssoSessionIdleTimeout" : 1800, - "ssoSessionMaxLifespan" : 36000, + "ssoSessionIdleTimeout" : 28800, + "ssoSessionMaxLifespan" : 604800, "ssoSessionIdleTimeoutRememberMe" : 0, "ssoSessionMaxLifespanRememberMe" : 0, "offlineSessionIdleTimeout" : 2592000, @@ -21,18 +22,20 @@ "clientOfflineSessionMaxLifespan" : 0, "accessCodeLifespan" : 60, "accessCodeLifespanUserAction" : 300, - "accessCodeLifespanLogin" : 1800, + "accessCodeLifespanLogin" : 28800, "actionTokenGeneratedByAdminLifespan" : 43200, "actionTokenGeneratedByUserLifespan" : 300, + "oauth2DeviceCodeLifespan" : 600, + "oauth2DevicePollingInterval" : 5, "enabled" : true, "sslRequired" : "external", "registrationAllowed" : false, "registrationEmailAsUsername" : false, - "rememberMe" : false, + "rememberMe" : true, "verifyEmail" : false, "loginWithEmailAllowed" : true, "duplicateEmailsAllowed" : false, - "resetPasswordAllowed" : false, + "resetPasswordAllowed" : true, "editUsernameAllowed" : false, "bruteForceProtected" : false, "permanentLockout" : false, @@ -52,13 +55,10 @@ "containerId" : "c4po_realm_local", "attributes" : { } }, { - "id" : "1fabc468-65bf-4651-8436-7d8d6a3a79e7", + "id" : "14eac93b-242a-4058-ba97-cf1f05a1e2ca", "name" : "c4po_user", - "description" : "This is a normal c4po User role", - "composite" : true, - "composites" : { - "realm" : [ "offline_access", "uma_authorization" ] - }, + "description" : "This is a normal user role", + "composite" : false, "clientRole" : false, "containerId" : "c4po_realm_local", "attributes" : { } @@ -73,10 +73,24 @@ }, { "id" : "3dc67a08-dc0a-4bb1-8808-b49bbf4611b0", "name" : "c4po_admin", - "description" : "This is an c4po admin role", + "description" : "This is an admin role", "composite" : true, "composites" : { - "realm" : [ "c4po_user", "offline_access", "uma_authorization" ] + "realm" : [ "offline_access", "uma_authorization" ] + }, + "clientRole" : false, + "containerId" : "c4po_realm_local", + "attributes" : { } + }, { + "id" : "da9911ce-ab0d-4a99-b73a-0ed6ca0406a7", + "name" : "default-roles-c4po_realm_local", + "description" : "${role_default-roles}", + "composite" : true, + "composites" : { + "realm" : [ "offline_access", "uma_authorization" ], + "client" : { + "account" : [ "view-profile", "manage-account" ] + } }, "clientRole" : false, "containerId" : "c4po_realm_local", @@ -108,17 +122,17 @@ "containerId" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", "attributes" : { } }, { - "id" : "3e152bff-b1b3-491e-8b41-5824f417357e", - "name" : "query-groups", - "description" : "${role_query-groups}", + "id" : "82f7b76d-b528-4fd5-aa9f-d89f1df9e1e1", + "name" : "impersonation", + "description" : "${role_impersonation}", "composite" : false, "clientRole" : true, "containerId" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", "attributes" : { } }, { - "id" : "82f7b76d-b528-4fd5-aa9f-d89f1df9e1e1", - "name" : "impersonation", - "description" : "${role_impersonation}", + "id" : "3e152bff-b1b3-491e-8b41-5824f417357e", + "name" : "query-groups", + "description" : "${role_query-groups}", "composite" : false, "clientRole" : true, "containerId" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", @@ -153,17 +167,17 @@ "containerId" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", "attributes" : { } }, { - "id" : "84338fd5-5a70-4c6a-b580-adb7416cb8b6", - "name" : "view-events", - "description" : "${role_view-events}", + "id" : "f36d5b71-6f9e-433e-a549-5f8dab3fa39d", + "name" : "query-realms", + "description" : "${role_query-realms}", "composite" : false, "clientRole" : true, "containerId" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", "attributes" : { } }, { - "id" : "f36d5b71-6f9e-433e-a549-5f8dab3fa39d", - "name" : "query-realms", - "description" : "${role_query-realms}", + "id" : "84338fd5-5a70-4c6a-b580-adb7416cb8b6", + "name" : "view-events", + "description" : "${role_view-events}", "composite" : false, "clientRole" : true, "containerId" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", @@ -185,17 +199,17 @@ "containerId" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", "attributes" : { } }, { - "id" : "7fcf212c-4371-48be-a75a-ec93830c4f8b", - "name" : "manage-users", - "description" : "${role_manage-users}", + "id" : "26f88bad-f69b-464f-89f1-43b987589173", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", "composite" : false, "clientRole" : true, "containerId" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", "attributes" : { } }, { - "id" : "26f88bad-f69b-464f-89f1-43b987589173", - "name" : "manage-authorization", - "description" : "${role_manage-authorization}", + "id" : "7fcf212c-4371-48be-a75a-ec93830c4f8b", + "name" : "manage-users", + "description" : "${role_manage-users}", "composite" : false, "clientRole" : true, "containerId" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", @@ -223,7 +237,7 @@ "composite" : true, "composites" : { "client" : { - "realm-management" : [ "query-groups", "query-users" ] + "realm-management" : [ "query-users", "query-groups" ] } }, "clientRole" : true, @@ -236,7 +250,7 @@ "composite" : true, "composites" : { "client" : { - "realm-management" : [ "create-client", "manage-clients", "manage-realm", "query-groups", "impersonation", "view-authorization", "view-clients", "manage-identity-providers", "view-events", "query-realms", "view-realm", "query-clients", "manage-users", "manage-authorization", "query-users", "manage-events", "view-users", "view-identity-providers" ] + "realm-management" : [ "create-client", "manage-clients", "manage-realm", "query-groups", "impersonation", "view-authorization", "view-clients", "manage-identity-providers", "view-events", "query-realms", "view-realm", "query-clients", "query-users", "manage-authorization", "manage-users", "manage-events", "view-users", "view-identity-providers" ] } }, "clientRole" : true, @@ -294,6 +308,22 @@ "clientRole" : true, "containerId" : "a7f62881-aa9e-4565-afeb-1d6305d3c56e", "attributes" : { } + }, { + "id" : "00ba6e25-3731-4363-9c07-3712aedf1ea8", + "name" : "view-groups", + "description" : "${role_view-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "a7f62881-aa9e-4565-afeb-1d6305d3c56e", + "attributes" : { } + }, { + "id" : "e772178b-5083-406b-84b5-e900a19f1a49", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "a7f62881-aa9e-4565-afeb-1d6305d3c56e", + "attributes" : { } }, { "id" : "f590afe8-3e54-491d-97b1-e29f56b22df3", "name" : "manage-account-links", @@ -335,7 +365,14 @@ } }, "groups" : [ ], - "defaultRoles" : [ "uma_authorization", "offline_access" ], + "defaultRole" : { + "id" : "da9911ce-ab0d-4a99-b73a-0ed6ca0406a7", + "name" : "default-roles-c4po_realm_local", + "description" : "${role_default-roles}", + "composite" : true, + "clientRole" : false, + "containerId" : "c4po_realm_local" + }, "requiredCredentials" : [ "password" ], "otpPolicyType" : "totp", "otpPolicyAlgorithm" : "HmacSHA1", @@ -343,7 +380,8 @@ "otpPolicyDigits" : 6, "otpPolicyLookAheadWindow" : 1, "otpPolicyPeriod" : 30, - "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ], + "otpPolicyCodeReusable" : false, + "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppFreeOTPName" ], "webAuthnPolicyRpEntityName" : "keycloak", "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], "webAuthnPolicyRpId" : "", @@ -365,52 +403,50 @@ "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], "users" : [ { - "id" : "f8aab31f-4925-4242-a6fa-f98135b4b031", - "createdTimestamp" : 1628265648730, - "username" : "aaa", + "id" : "7fd27f3e-2102-4531-ad77-2423d42568e7", + "createdTimestamp" : 1682073378356, + "username" : "admin", "enabled" : true, "totp" : false, "emailVerified" : false, - "firstName" : "test", + "firstName" : "admin", "lastName" : "admin", "credentials" : [ { - "id" : "2aef72e0-1728-429c-b55c-7ff7f3cf65aa", + "id" : "095476b7-53a3-4528-85bd-4e45bebd1155", "type" : "password", - "createdDate" : 1628265679465, - "secretData" : "{\"value\":\"50YE6HhI9bY+we+xCWDwMkWRWVylzSBmhuwZ5ZWfcnG35reKCQwJismV3PiU+URf4EpZtz7GXai1nB7tzfP7Og==\",\"salt\":\"ePpIxzR6oiOY7bmrsI+5EA==\"}", - "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}" + "userLabel" : "My password", + "createdDate" : 1682073413281, + "secretData" : "{\"value\":\"2ZAR9LLxAcwOezklS872x9jSq8d4oGulf45PkPNs5KroeI22UCdDdIsAafy++JpQgXwBl+5Co82gOclWR3fldA==\",\"salt\":\"tAfgELoKjIq6/grj0epu7A==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], "requiredActions" : [ ], - "realmRoles" : [ "uma_authorization", "offline_access", "c4po_admin" ], - "clientRoles" : { - "account" : [ "view-profile", "manage-account" ] - }, + "realmRoles" : [ "c4po_admin", "default-roles-c4po_realm_local" ], "notBefore" : 0, "groups" : [ ] }, { - "id" : "10e06d7a-8dd0-4ecd-8963-056b45079c4f", - "createdTimestamp" : 1617897245335, - "username" : "ttt", + "id" : "16a52c3d-998b-4f2d-badb-1f369d95a690", + "createdTimestamp" : 1682073624527, + "username" : "c4po", "enabled" : true, "totp" : false, "emailVerified" : false, - "firstName" : "test", - "lastName" : "user", + "firstName" : "Elliot", + "lastName" : "Alderson", + "attributes" : { + "locale" : [ "en" ] + }, "credentials" : [ { - "id" : "7026fefc-ae26-442b-acae-92f1f2d24eac", + "id" : "028e1f11-50c1-4b28-a521-b80469aa1ae0", "type" : "password", - "createdDate" : 1617897287400, - "secretData" : "{\"value\":\"mhW4yxOg+8bcyPF4yWsfPZnLGUp4oaqc9aNA+WBcpr9qXgs/Jw+rM2VlLEgeD/kXGItcScA8V20sVGrMWT94Yw==\",\"salt\":\"nkH510WAwjKZJqd/ZEkIHA==\"}", - "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}" + "userLabel" : "My password", + "createdDate" : 1682073686387, + "secretData" : "{\"value\":\"M/Sb4JgRZ0TSR49GI+Xh+QMhX3iAK84G6xfF5tCCz3z4bneEtyuggOn/HcNOfwSpxj1qetci5017gcjOYqc1+g==\",\"salt\":\"jvPAa8JX8WIwgPHsJVL2QQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], "requiredActions" : [ ], - "realmRoles" : [ "uma_authorization", "c4po_user" ], - "clientRoles" : { - "c4po_local" : [ "user" ], - "account" : [ "view-profile", "manage-account" ] - }, + "realmRoles" : [ "c4po_user", "default-roles-c4po_realm_local" ], "notBefore" : 0, "groups" : [ ] } ], @@ -421,7 +457,7 @@ "clientScopeMappings" : { "account" : [ { "client" : "account-console", - "roles" : [ "manage-account" ] + "roles" : [ "manage-account", "view-groups" ] } ] }, "clients" : [ { @@ -435,7 +471,6 @@ "alwaysDisplayInConsole" : false, "clientAuthenticatorType" : "client-secret", "secret" : "**********", - "defaultRoles" : [ "view-profile", "manage-account" ], "redirectUris" : [ "/realms/c4po_realm_local/account/*" ], "webOrigins" : [ ], "notBefore" : 0, @@ -448,11 +483,13 @@ "publicClient" : false, "frontchannelLogout" : false, "protocol" : "openid-connect", - "attributes" : { }, + "attributes" : { + "post.logout.redirect.uris" : "+" + }, "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : false, "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "da51d616-1ca6-4434-a16d-b543d2a4e4c0", @@ -478,6 +515,7 @@ "frontchannelLogout" : false, "protocol" : "openid-connect", "attributes" : { + "post.logout.redirect.uris" : "+", "pkce.code.challenge.method" : "S256" }, "authenticationFlowBindingOverrides" : { }, @@ -491,7 +529,7 @@ "consentRequired" : false, "config" : { } } ], - "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "63cb2215-d2f1-4229-96fc-82fb843e283a", @@ -514,11 +552,13 @@ "publicClient" : true, "frontchannelLogout" : false, "protocol" : "openid-connect", - "attributes" : { }, + "attributes" : { + "post.logout.redirect.uris" : "+" + }, "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : false, "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "f90fb534-a4bf-4e08-b0d3-8a5552eb5a12", @@ -541,20 +581,26 @@ "publicClient" : false, "frontchannelLogout" : false, "protocol" : "openid-connect", - "attributes" : { }, + "attributes" : { + "post.logout.redirect.uris" : "+" + }, "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : false, "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "6cbc559d-073e-40d7-8b73-b2dcdc438461", "clientId" : "c4po_local", + "name" : "", + "description" : "", + "rootUrl" : "", + "adminUrl" : "", + "baseUrl" : "", "surrogateAuthRequired" : false, "enabled" : true, "alwaysDisplayInConsole" : false, "clientAuthenticatorType" : "client-secret", - "secret" : "**********", "redirectUris" : [ "http://localhost:4200/*" ], "webOrigins" : [ "*" ], "notBefore" : 0, @@ -572,9 +618,15 @@ "saml.force.post.binding" : "false", "saml.multivalued.roles" : "false", "saml.encrypt" : "false", + "frontchannel.logout.url" : "/logout", + "post.logout.redirect.uris" : "*", + "oauth2.device.authorization.grant.enabled" : "false", "saml.server.signature" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", "saml.server.signature.keyinfo.ext" : "false", "exclude.session.state.from.auth.response" : "false", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "true", "saml_force_name_id_format" : "false", "saml.client.signature" : "false", "tls.client.certificate.bound.access.tokens" : "false", @@ -585,7 +637,7 @@ "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : true, "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "fa74c4e8-a9c0-4fa9-bb21-2ad3535b08ef", @@ -608,11 +660,13 @@ "publicClient" : false, "frontchannelLogout" : false, "protocol" : "openid-connect", - "attributes" : { }, + "attributes" : { + "post.logout.redirect.uris" : "+" + }, "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : false, "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "7e165a51-6cb8-43cf-a4fe-1d0ad513586b", @@ -638,6 +692,7 @@ "frontchannelLogout" : false, "protocol" : "openid-connect", "attributes" : { + "post.logout.redirect.uris" : "+", "pkce.code.challenge.method" : "S256" }, "authenticationFlowBindingOverrides" : { }, @@ -658,11 +713,13 @@ "jsonType.label" : "String" } } ], - "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "7f731c1c-4fd8-470a-a995-b242fc5b550d", "clientId" : "security-c4po-angular", + "name" : "", + "description" : "", "rootUrl" : "", "adminUrl" : "", "baseUrl" : "http://localhost:4200/", @@ -688,9 +745,14 @@ "saml.force.post.binding" : "false", "saml.multivalued.roles" : "false", "saml.encrypt" : "false", + "post.logout.redirect.uris" : "*", + "oauth2.device.authorization.grant.enabled" : "false", "saml.server.signature" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", "saml.server.signature.keyinfo.ext" : "false", "exclude.session.state.from.auth.response" : "false", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "true", "saml_force_name_id_format" : "false", "saml.client.signature" : "false", "tls.client.certificate.bound.access.tokens" : "false", @@ -701,11 +763,13 @@ "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : true, "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "8badc11a-50e4-44ae-a292-47e3759fcaeb", "clientId" : "security-c4po-api", + "name" : "", + "description" : "", "rootUrl" : "", "adminUrl" : "", "baseUrl" : "http://localhost:8443/", @@ -731,9 +795,14 @@ "saml.force.post.binding" : "false", "saml.multivalued.roles" : "false", "saml.encrypt" : "false", + "post.logout.redirect.uris" : "*", + "oauth2.device.authorization.grant.enabled" : "false", "saml.server.signature" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", "saml.server.signature.keyinfo.ext" : "false", "exclude.session.state.from.auth.response" : "false", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "true", "saml_force_name_id_format" : "false", "saml.client.signature" : "false", "tls.client.certificate.bound.access.tokens" : "false", @@ -744,19 +813,10 @@ "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : true, "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] } ], "clientScopes" : [ { - "id" : "8d428e56-80df-4505-8e1a-26537e793b31", - "name" : "offline_access", - "description" : "OpenID Connect built-in scope: offline_access", - "protocol" : "openid-connect", - "attributes" : { - "consent.screen.text" : "${offlineAccessScopeConsentText}", - "display.on.consent.screen" : "true" - } - }, { "id" : "4b171f57-736a-41b4-b67b-585bac1d8d24", "name" : "role_list", "description" : "SAML role list", @@ -777,6 +837,15 @@ "attribute.name" : "Role" } } ] + }, { + "id" : "8d428e56-80df-4505-8e1a-26537e793b31", + "name" : "offline_access", + "description" : "OpenID Connect built-in scope: offline_access", + "protocol" : "openid-connect", + "attributes" : { + "consent.screen.text" : "${offlineAccessScopeConsentText}", + "display.on.consent.screen" : "true" + } }, { "id" : "ac7d05f9-d505-42e9-9b7c-1984b31e653d", "name" : "profile", @@ -981,73 +1050,6 @@ "jsonType.label" : "String" } } ] - }, { - "id" : "32f1098d-79a9-4da4-a94a-c873fcc0f6e1", - "name" : "email", - "description" : "OpenID Connect built-in scope: email", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${emailScopeConsentText}" - }, - "protocolMappers" : [ { - "id" : "92afef33-2843-40bc-aba1-58d462fa81cc", - "name" : "email verified", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "userinfo.token.claim" : "true", - "user.attribute" : "emailVerified", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email_verified", - "jsonType.label" : "boolean" - } - }, { - "id" : "4b4d33d1-ed47-40db-a05f-4253c25dbbff", - "name" : "email", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "userinfo.token.claim" : "true", - "user.attribute" : "email", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "412cfb80-d33e-44da-a0e2-b0bde0423c00", - "name" : "address", - "description" : "OpenID Connect built-in scope: address", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${addressScopeConsentText}" - }, - "protocolMappers" : [ { - "id" : "261a490f-073d-4975-af5b-e2d9e21ea768", - "name" : "address", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-address-mapper", - "consentRequired" : false, - "config" : { - "user.attribute.formatted" : "formatted", - "user.attribute.country" : "country", - "user.attribute.postal_code" : "postal_code", - "userinfo.token.claim" : "true", - "user.attribute.street" : "street", - "id.token.claim" : "true", - "user.attribute.region" : "region", - "access.token.claim" : "true", - "user.attribute.locality" : "locality" - } - } ] }, { "id" : "faf5c077-e43d-4433-9f5d-ddfc10f31385", "name" : "phone", @@ -1131,24 +1133,6 @@ "consentRequired" : false, "config" : { } } ] - }, { - "id" : "cd5f153a-ff23-43d5-81a0-6c8dc6f39a4e", - "name" : "web-origins", - "description" : "OpenID Connect scope for add allowed web origins to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false", - "consent.screen.text" : "" - }, - "protocolMappers" : [ { - "id" : "9a8031f8-997b-4899-ba60-05868f8e4b18", - "name" : "allowed web origins", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-allowed-origins-mapper", - "consentRequired" : false, - "config" : { } - } ] }, { "id" : "b18623a4-3595-4993-b2bd-79e94778d28b", "name" : "microprofile-jwt", @@ -1188,8 +1172,114 @@ "jsonType.label" : "String" } } ] + }, { + "id" : "412cfb80-d33e-44da-a0e2-b0bde0423c00", + "name" : "address", + "description" : "OpenID Connect built-in scope: address", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${addressScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "261a490f-073d-4975-af5b-e2d9e21ea768", + "name" : "address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-address-mapper", + "consentRequired" : false, + "config" : { + "user.attribute.formatted" : "formatted", + "user.attribute.country" : "country", + "user.attribute.postal_code" : "postal_code", + "userinfo.token.claim" : "true", + "user.attribute.street" : "street", + "id.token.claim" : "true", + "user.attribute.region" : "region", + "access.token.claim" : "true", + "user.attribute.locality" : "locality" + } + } ] + }, { + "id" : "cd5f153a-ff23-43d5-81a0-6c8dc6f39a4e", + "name" : "web-origins", + "description" : "OpenID Connect scope for add allowed web origins to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false", + "consent.screen.text" : "" + }, + "protocolMappers" : [ { + "id" : "9a8031f8-997b-4899-ba60-05868f8e4b18", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { } + } ] + }, { + "id" : "aeab50c1-fd64-4f14-83d9-2c545a23f77c", + "name" : "acr", + "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "a70e5d7f-734e-4838-96a1-67cd713f3c9e", + "name" : "acr loa level", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-acr-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + } ] + }, { + "id" : "32f1098d-79a9-4da4-a94a-c873fcc0f6e1", + "name" : "email", + "description" : "OpenID Connect built-in scope: email", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${emailScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "92afef33-2843-40bc-aba1-58d462fa81cc", + "name" : "email verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "emailVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email_verified", + "jsonType.label" : "boolean" + } + }, { + "id" : "4b4d33d1-ed47-40db-a05f-4253c25dbbff", + "name" : "email", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "email", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email", + "jsonType.label" : "String" + } + } ] } ], - "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins" ], + "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins", "acr" ], "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt" ], "browserSecurityHeaders" : { "contentSecurityPolicyReportOnly" : "", @@ -1206,6 +1296,8 @@ "enabledEventTypes" : [ ], "adminEventsEnabled" : false, "adminEventsDetailsEnabled" : false, + "identityProviders" : [ ], + "identityProviderMappers" : [ ], "components" : { "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { "id" : "56f53138-a448-42f5-ba77-b026b1b179d0", @@ -1232,7 +1324,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "saml-user-property-mapper" ] } }, { "id" : "cc2d0cd7-3d3f-4b0a-ad95-7118f36bf188", @@ -1264,7 +1356,7 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "saml-role-list-mapper" ] } }, { "id" : "92230e65-7480-44c3-af2d-72ddee758cbc", @@ -1277,6 +1369,12 @@ "client-uris-must-match" : [ "true" ] } } ], + "org.keycloak.userprofile.UserProfileProvider" : [ { + "id" : "d3115ef0-4137-41c5-9e7f-35ace4f7b43e", + "providerId" : "declarative-user-profile", + "subComponents" : { }, + "config" : { } + } ], "org.keycloak.keys.KeyProvider" : [ { "id" : "ea025a18-d77a-4bbc-8e3a-c6b55ccf4b3f", "name" : "hmac-generated", @@ -1310,10 +1408,11 @@ } } ] }, - "internationalizationEnabled" : false, - "supportedLocales" : [ ], + "internationalizationEnabled" : true, + "supportedLocales" : [ "de", "en" ], + "defaultLocale" : "en", "authenticationFlows" : [ { - "id" : "15c4eeb8-2a2b-4e5e-b5e1-98509003683b", + "id" : "0296b89f-2d7b-4931-b4ce-72167e83d8b7", "alias" : "Account verification options", "description" : "Method with which to verity the existing account", "providerId" : "basic-flow", @@ -1321,19 +1420,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "idp-email-verification", + "authenticatorFlow" : false, "requirement" : "ALTERNATIVE", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "ALTERNATIVE", "priority" : 20, + "autheticatorFlow" : true, "flowAlias" : "Verify Existing Account by Re-authentication", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "e1240eb6-5e97-443f-9759-107179344936", + "id" : "64a2976c-5625-41a2-97d7-b53e78cc3a92", "alias" : "Authentication Options", "description" : "Authentication options.", "providerId" : "basic-flow", @@ -1341,25 +1442,28 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "basic-auth", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "basic-auth-otp", + "authenticatorFlow" : false, "requirement" : "DISABLED", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "auth-spnego", + "authenticatorFlow" : false, "requirement" : "DISABLED", "priority" : 30, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false } ] }, { - "id" : "89fcc224-8b2a-4a3f-9b3e-abb9d577cacc", + "id" : "23dce318-8864-429d-8e42-8f60adf87bb8", "alias" : "Browser - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -1367,19 +1471,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false } ] }, { - "id" : "74e9fa48-2fed-41c9-afa7-3a4beae840ce", + "id" : "07c663a3-9361-4fb1-ac6f-6af140b9d8b5", "alias" : "Direct Grant - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -1387,19 +1493,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "direct-grant-validate-otp", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false } ] }, { - "id" : "b898b1e5-7746-4c73-a441-36e7fde9f25b", + "id" : "8a797183-07fc-44a1-80a5-bfa6b4d727e1", "alias" : "First broker login - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -1407,19 +1515,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false } ] }, { - "id" : "0498a97c-0af7-4316-b5d5-5a3ddbfcd390", + "id" : "98e3631a-0ff2-4528-b835-4836d755b430", "alias" : "Handle Existing Account", "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", "providerId" : "basic-flow", @@ -1427,19 +1537,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "idp-confirm-link", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "REQUIRED", "priority" : 20, + "autheticatorFlow" : true, "flowAlias" : "Account verification options", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "510b541f-9a5a-4525-bb72-638c6aba43ca", + "id" : "849a9f5a-0389-4de4-8da7-9561a1e266e8", "alias" : "Reset - Conditional OTP", "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", "providerId" : "basic-flow", @@ -1447,19 +1559,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "reset-otp", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false } ] }, { - "id" : "6490f472-d3db-47ce-ba4f-7e8b8048dec5", + "id" : "e196e161-37ce-4616-be7f-b1742c4f7453", "alias" : "User creation or linking", "description" : "Flow for the existing/non-existing user alternatives", "providerId" : "basic-flow", @@ -1468,19 +1582,21 @@ "authenticationExecutions" : [ { "authenticatorConfig" : "create unique user config", "authenticator" : "idp-create-user-if-unique", + "authenticatorFlow" : false, "requirement" : "ALTERNATIVE", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "ALTERNATIVE", "priority" : 20, + "autheticatorFlow" : true, "flowAlias" : "Handle Existing Account", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "0cfd20ab-4c6f-4af2-a01f-eef718f79d24", + "id" : "ab6e417d-91a9-4a2e-a288-230b30ed2608", "alias" : "Verify Existing Account by Re-authentication", "description" : "Reauthentication of existing account", "providerId" : "basic-flow", @@ -1488,19 +1604,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "idp-username-password-form", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "CONDITIONAL", "priority" : 20, + "autheticatorFlow" : true, "flowAlias" : "First broker login - Conditional OTP", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "c91d3ef4-70ab-4be0-a9ec-abd17564ef9f", + "id" : "ed177a27-8acf-46c9-aecd-66a9de099b71", "alias" : "browser", "description" : "browser based authentication", "providerId" : "basic-flow", @@ -1508,31 +1626,35 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "auth-cookie", + "authenticatorFlow" : false, "requirement" : "ALTERNATIVE", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "auth-spnego", + "authenticatorFlow" : false, "requirement" : "DISABLED", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "identity-provider-redirector", + "authenticatorFlow" : false, "requirement" : "ALTERNATIVE", "priority" : 25, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "ALTERNATIVE", "priority" : 30, + "autheticatorFlow" : true, "flowAlias" : "forms", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "0a39ae03-c439-41ec-b9bc-e4defb358422", + "id" : "7e14a81b-508b-4a78-aeca-c783e209209d", "alias" : "clients", "description" : "Base authentication for clients", "providerId" : "client-flow", @@ -1540,31 +1662,35 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "client-secret", + "authenticatorFlow" : false, "requirement" : "ALTERNATIVE", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "client-jwt", + "authenticatorFlow" : false, "requirement" : "ALTERNATIVE", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "client-secret-jwt", + "authenticatorFlow" : false, "requirement" : "ALTERNATIVE", "priority" : 30, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "client-x509", + "authenticatorFlow" : false, "requirement" : "ALTERNATIVE", "priority" : 40, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false } ] }, { - "id" : "2f793704-d04e-4fe8-8cc2-c8467a3f140e", + "id" : "6e52e23e-d83f-46c2-bc4d-e336999e2293", "alias" : "direct grant", "description" : "OpenID Connect Resource Owner Grant", "providerId" : "basic-flow", @@ -1572,25 +1698,28 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "direct-grant-validate-username", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "direct-grant-validate-password", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "CONDITIONAL", "priority" : 30, + "autheticatorFlow" : true, "flowAlias" : "Direct Grant - Conditional OTP", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "555d28c6-c9c7-43ec-94de-6cfea6a3cd14", + "id" : "6d476080-ebc3-4bce-90ac-93afc891a83e", "alias" : "docker auth", "description" : "Used by Docker clients to authenticate against the IDP", "providerId" : "basic-flow", @@ -1598,13 +1727,14 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "docker-http-basic-authenticator", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false } ] }, { - "id" : "d6c01d47-329c-4333-8eac-5a8409f7bde8", + "id" : "1143f6ea-867a-4b08-974e-86a4b9ba8601", "alias" : "first broker login", "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", "providerId" : "basic-flow", @@ -1613,19 +1743,21 @@ "authenticationExecutions" : [ { "authenticatorConfig" : "review profile config", "authenticator" : "idp-review-profile", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "REQUIRED", "priority" : 20, + "autheticatorFlow" : true, "flowAlias" : "User creation or linking", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "00bd3ccb-23cc-4a04-8c8f-83556bd7deaf", + "id" : "2090f383-dcab-441c-9f37-5b37504a1692", "alias" : "forms", "description" : "Username, password, otp and other auth forms.", "providerId" : "basic-flow", @@ -1633,19 +1765,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "auth-username-password-form", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "CONDITIONAL", "priority" : 20, + "autheticatorFlow" : true, "flowAlias" : "Browser - Conditional OTP", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "6cd5ce9b-6a5c-4c2c-bd19-fb2f310aecc4", + "id" : "13395ad8-a0eb-42f4-9d9d-c715c717d181", "alias" : "http challenge", "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes", "providerId" : "basic-flow", @@ -1653,19 +1787,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "no-cookie-redirect", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "REQUIRED", "priority" : 20, + "autheticatorFlow" : true, "flowAlias" : "Authentication Options", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "5549dba2-1397-4f89-aff5-49ca823cabb8", + "id" : "a656e7fc-fa52-46e3-9fc1-654cafe37087", "alias" : "registration", "description" : "registration flow", "providerId" : "basic-flow", @@ -1673,14 +1809,15 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "registration-page-form", + "authenticatorFlow" : true, "requirement" : "REQUIRED", "priority" : 10, + "autheticatorFlow" : true, "flowAlias" : "registration form", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "ac076c79-3b2f-437a-8255-247eb2ce28b6", + "id" : "84e1ffa9-3dd8-4b32-8cd9-e4bbc4631624", "alias" : "registration form", "description" : "registration form", "providerId" : "form-flow", @@ -1688,31 +1825,35 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "registration-user-creation", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "registration-profile-action", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 40, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "registration-password-action", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 50, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "registration-recaptcha-action", + "authenticatorFlow" : false, "requirement" : "DISABLED", "priority" : 60, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false } ] }, { - "id" : "51219395-2175-4be5-8975-e844bbe8985e", + "id" : "68dad811-63ec-484a-a0b9-9656edc6921e", "alias" : "reset credentials", "description" : "Reset credentials for a user if they forgot their password or something", "providerId" : "basic-flow", @@ -1720,31 +1861,35 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "reset-credentials-choose-user", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "reset-credential-email", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { "authenticator" : "reset-password", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 30, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false }, { + "authenticatorFlow" : true, "requirement" : "CONDITIONAL", "priority" : 40, + "autheticatorFlow" : true, "flowAlias" : "Reset - Conditional OTP", - "userSetupAllowed" : false, - "autheticatorFlow" : true + "userSetupAllowed" : false } ] }, { - "id" : "b6131d9d-55b2-40a5-9b36-f0b1ef662554", + "id" : "9a212f2d-80ae-4051-9d09-28d016809204", "alias" : "saml ecp", "description" : "SAML ECP Profile Authentication Flow", "providerId" : "basic-flow", @@ -1752,20 +1897,21 @@ "builtIn" : true, "authenticationExecutions" : [ { "authenticator" : "http-basic-authenticator", + "authenticatorFlow" : false, "requirement" : "REQUIRED", "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false + "autheticatorFlow" : false, + "userSetupAllowed" : false } ] } ], "authenticatorConfig" : [ { - "id" : "d818257f-52f2-461e-b587-55b7a4dc968f", + "id" : "9e437782-7c8f-4732-a1e6-cd84abdf78e3", "alias" : "create unique user config", "config" : { "require.password.update.after.registration" : "false" } }, { - "id" : "6e3771dd-8647-4cff-9bc4-49d824fb0582", + "id" : "8d01fb5d-be3d-42d9-ae27-592fab7d8d14", "alias" : "review profile config", "config" : { "update.profile.on.first.login" : "missing" @@ -1811,6 +1957,14 @@ "defaultAction" : false, "priority" : 50, "config" : { } + }, { + "alias" : "delete_account", + "name" : "Delete Account", + "providerId" : "delete_account", + "enabled" : false, + "defaultAction" : false, + "priority" : 60, + "config" : { } }, { "alias" : "update_user_locale", "name" : "Update User Locale", @@ -1827,11 +1981,29 @@ "clientAuthenticationFlow" : "clients", "dockerAuthenticationFlow" : "docker auth", "attributes" : { + "cibaBackchannelTokenDeliveryMode" : "poll", + "cibaAuthRequestedUserHint" : "login_hint", "clientOfflineSessionMaxLifespan" : "0", + "oauth2DevicePollingInterval" : "5", "clientSessionIdleTimeout" : "0", - "clientSessionMaxLifespan" : "0", - "clientOfflineSessionIdleTimeout" : "0" + "actionTokenGeneratedByUserLifespan-execute-actions" : "", + "actionTokenGeneratedByUserLifespan-verify-email" : "", + "clientOfflineSessionIdleTimeout" : "0", + "actionTokenGeneratedByUserLifespan-reset-credentials" : "", + "cibaInterval" : "5", + "realmReusableOtpCode" : "false", + "cibaExpiresIn" : "120", + "oauth2DeviceCodeLifespan" : "600", + "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "", + "parRequestUriLifespan" : "60", + "clientSessionMaxLifespan" : "0" }, - "keycloakVersion" : "11.0.3", - "userManagedAccessAllowed" : false + "keycloakVersion" : "20.0.0", + "userManagedAccessAllowed" : false, + "clientProfiles" : { + "profiles" : [ ] + }, + "clientPolicies" : { + "policies" : [ ] + } } \ No newline at end of file diff --git a/security-c4po-cfg/docker-compose.yml b/security-c4po-cfg/docker-compose.yml index 6b5eb35..480142d 100644 --- a/security-c4po-cfg/docker-compose.yml +++ b/security-c4po-cfg/docker-compose.yml @@ -64,6 +64,22 @@ services: - 8443:8443 networks: - c4po + c4po-reporting: + build: '../security-c4po-reporting' + image: security-c4po-reporting:latest + container_name: c4po-reporting + environment: + - SPRING_PROFILES_ACTIVE=COMPOSE + depends_on: + - c4po-keycloak + deploy: + resources: + limits: + memory: "4G" + ports: + - 8444:8444 + networks: + - c4po networks: c4po: diff --git a/security-c4po-reporting/Dockerfile b/security-c4po-reporting/Dockerfile index 79115ea..73b9155 100644 --- a/security-c4po-reporting/Dockerfile +++ b/security-c4po-reporting/Dockerfile @@ -15,6 +15,7 @@ COPY ./build/libs/security-c4po-reporting-0.0.1-SNAPSHOT.jar / USER security-c4po-reporting EXPOSE 8444 -# RUN JAVA +# WAIT FOR KEYCLOAK & RUN JAVA +COPY ./wait-for-keycloak.sh / # CMD [ "java", "-jar", "security-c4po-reporting-0.0.1-SNAPSHOT.jar" ] -ENTRYPOINT [ "java", "-jar", "-Dspring.profiles.active=${ENV_STAGE}", "security-c4po-reporting-0.0.1-SNAPSHOT.jar" ] +ENTRYPOINT [ "./wait-for-keycloak.sh", "http://c4po-keycloak:8080/auth/realms/c4po_realm_local", "java", "-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}", "-jar", "security-c4po-reporting-0.0.1-SNAPSHOT.jar" ] diff --git a/security-c4po-reporting/build.gradle.kts b/security-c4po-reporting/build.gradle.kts index 038ba4f..fc023d1 100644 --- a/security-c4po-reporting/build.gradle.kts +++ b/security-c4po-reporting/build.gradle.kts @@ -62,7 +62,7 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.springframework.boot:spring-boot-starter-actuator") - + // Security implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-oauth2-client") implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") diff --git a/security-c4po-reporting/src/main/kotlin/com/securityc4po/reporting/report/ReportController.kt b/security-c4po-reporting/src/main/kotlin/com/securityc4po/reporting/report/ReportController.kt index cfca13e..3596276 100644 --- a/security-c4po-reporting/src/main/kotlin/com/securityc4po/reporting/report/ReportController.kt +++ b/security-c4po-reporting/src/main/kotlin/com/securityc4po/reporting/report/ReportController.kt @@ -37,8 +37,6 @@ class ReportController(private val apiService: APIService, private val reportSer ResponseEntity.ok().body(reportClassLoaderFilePath) }.switchIfEmpty { Mono.just(notFound().build()) - }.doOnSuccess { - this.reportService.cleanUpFiles() } } } diff --git a/security-c4po-reporting/src/main/kotlin/com/securityc4po/reporting/report/ReportService.kt b/security-c4po-reporting/src/main/kotlin/com/securityc4po/reporting/report/ReportService.kt index eb97733..5af266b 100644 --- a/security-c4po-reporting/src/main/kotlin/com/securityc4po/reporting/report/ReportService.kt +++ b/security-c4po-reporting/src/main/kotlin/com/securityc4po/reporting/report/ReportService.kt @@ -2,19 +2,15 @@ package com.securityc4po.reporting.report import com.securityc4po.reporting.extensions.getLoggerFor import com.securityc4po.reporting.remote.model.* -import com.securityc4po.reporting.remote.model.api.Comment -import com.securityc4po.reporting.remote.model.api.Finding import net.sf.jasperreports.engine.* import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource -import org.apache.commons.io.FileUtils import org.apache.pdfbox.io.MemoryUsageSetting import org.apache.pdfbox.multipdf.PDFMergerUtility +import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Service -import org.springframework.util.ResourceUtils import reactor.core.publisher.Flux import reactor.core.publisher.Mono -import java.io.ByteArrayOutputStream -import java.io.File +import java.io.* @Service @@ -26,59 +22,68 @@ class ReportService { var logger = getLoggerFor() - private val reportCoverDesignTemplate = "./src/main/resources/jasper/reports/c4po_cover.jrxml" - private val reportContentDesignTemplate = "./src/main/resources/jasper/reports/c4po_content.jrxml" - private val reportStateOfConfidentialityDesignTemplate = - "./src/main/resources/jasper/reports/c4po_state_of_confidentiality.jrxml" - private val reportExecutiveSummaryDesignTemplate = - "./src/main/resources/jasper/reports/c4po_executive_summary.jrxml" - private val reportPentestsFindingsAndCommentsDesignTemplate = "./src/main/resources/jasper/reports/c4po_pentests_findings_and_comments.jrxml" - private val reportPentestsFindingsOnlyDesignTemplate = "./src/main/resources/jasper/reports/c4po_pentests_findings_only.jrxml" - private val reportPentestsCommentsOnlyDesignTemplate = "./src/main/resources/jasper/reports/c4po_pentests_comments_only.jrxml" - private val reportAppendenciesDesignTemplate = "./src/main/resources/jasper/reports/c4po_appendencies.jrxml" + // Jasper Design template file Paths + @Value("\${reportCoverDesignTemplate}") + lateinit var reportCoverDesignTemplate: String + + @Value("\${reportContentDesignTemplate}") + lateinit var reportContentDesignTemplate: String + + @Value("\${reportStateOfConfidentialityDesignTemplate}") + lateinit var reportStateOfConfidentialityDesignTemplate: String + + @Value("\${reportExecutiveSummaryDesignTemplate}") + lateinit var reportExecutiveSummaryDesignTemplate: String + + @Value("\${reportPentestsFindingsAndCommentsDesignTemplate}") + lateinit var reportPentestsFindingsAndCommentsDesignTemplate: String + + @Value("\${reportPentestsFindingsOnlyDesignTemplate}") + lateinit var reportPentestsFindingsOnlyDesignTemplate: String + + @Value("\${reportPentestsCommentsOnlyDesignTemplate}") + lateinit var reportPentestsCommentsOnlyDesignTemplate: String + + @Value("\${reportAppendenciesDesignTemplate}") + lateinit var reportAppendenciesDesignTemplate: String // Path to default pdf file - private val reportDefaultPdf = "./src/main/resources/jasper/DEFAULT.pdf" + @Value("\${reportDefaultPdf}") + lateinit var reportDefaultPdfPropertyPath: String - // Path where the created Reports are saved - private val reportDestination = "./src/main/resources/jasper/reportPDFs/" + // Image paths + @Value("\${CDATA_WATERMARK}") + lateinit var waterMarkPath: String - // Path where the completed Report is saved - private val reportFileDestination = "./src/main/resources/jasper/finalReport/" + @Value("\${CDATA_C4POCoverBackground}") + lateinit var coverBackgroundPath: String - // Path where the completed Report can be found by class loader - private val reportFileForClassLoader = "/jasper/finalReport/" + // Subreport paths + @Value("\${CDATA_FindingsSubreport}") + lateinit var findingsSubreportPath: String + + @Value("\${CDATA_CommentsSubreport}") + lateinit var commentsSubreportPath: String + + @Value("\${CDATA_SeverityRatingTable}") + lateinit var severityRatingTablePath: String fun createReport(projectReportCollection: ProjectReport, reportFormat: String): Mono { - // Setup Filepath destination - val reportFilePathDestination: String = - reportFileDestination + projectReportCollection.title.replace(" ", "_") + "_report.pdf" // Setup PDFMergerUtility val mergedC4POPentestReport: PDFMergerUtility = PDFMergerUtility() // Setup ByteArrayOutputStream for "on the fly" file generation val pdfDocOutputstream = ByteArrayOutputStream() // Try to create report files & merge them together - return createPentestReportFiles(projectReportCollection, reportFormat, mergedC4POPentestReport).collectList().map { - // Merge report files - mergedC4POPentestReport.destinationFileName = reportFilePathDestination - mergedC4POPentestReport.destinationStream = pdfDocOutputstream - mergedC4POPentestReport.mergeDocuments(MemoryUsageSetting.setupTempFileOnly()) - }.flatMap { - return@flatMap Mono.just(pdfDocOutputstream.toByteArray()) - }.doOnError { - logger.error("Report generation failed.") - } - } - - fun cleanUpFiles() { - val cleanUpDirectoryReportsPath = "./src/main/resources/jasper/reportPDFs" - val cleanUpDirectoryCompletedReportsPath = "./src/main/resources/jasper/finalReport" - try { - FileUtils.cleanDirectory(File(cleanUpDirectoryReportsPath)) - FileUtils.cleanDirectory(File(cleanUpDirectoryCompletedReportsPath)) - } catch (e: Exception) { - logger.error("Report file cleanup failed with exception: ", e) - } + return createPentestReportFiles(projectReportCollection, reportFormat, mergedC4POPentestReport).collectList() + .map { + // Merge report files + mergedC4POPentestReport.destinationStream = pdfDocOutputstream + mergedC4POPentestReport.mergeDocuments(MemoryUsageSetting.setupTempFileOnly()) + }.flatMap { + return@flatMap Mono.just(pdfDocOutputstream.toByteArray()) + }.doOnError { + logger.error("Report generation failed.") + } } private fun createPentestReportFiles( @@ -87,7 +92,7 @@ class ReportService { mergedC4POPentestReport: PDFMergerUtility ): Flux { return Flux.just( - // Create report files + // Create byte arrays of report files createCover(projectReportCollection, reportFormat), createTableOfContent(projectReportCollection, reportFormat), createStateOfConfidentiality(projectReportCollection, reportFormat), @@ -95,298 +100,358 @@ class ReportService { createPentestReports(projectReportCollection, reportFormat), createAppendencies(reportFormat) ).map { jasperObject -> - if (jasperObject is File) { - mergedC4POPentestReport.addSource(jasperObject) + if (jasperObject is ByteArray) { + val pdfInputSteam = ByteArrayInputStream(jasperObject) + mergedC4POPentestReport.addSource(pdfInputSteam) } else if (jasperObject is List<*>) { jasperObject.forEach { jasperFile -> - if (jasperFile is File) { - mergedC4POPentestReport.addSource(jasperFile) + if (jasperFile is ByteArray) { + val pdfInputSteam = ByteArrayInputStream(jasperFile) + mergedC4POPentestReport.addSource(pdfInputSteam) } } } } } - private fun createCover(projectReportCollection: ProjectReport, reportFormat: String): File { + private fun createCover(projectReportCollection: ProjectReport, reportFormat: String): ByteArray { // Load Jasper Files - val fileCover: File = ResourceUtils.getFile(reportCoverDesignTemplate) - // Compile Jasper Reports - val jasperReportCover: JasperReport = JasperCompileManager.compileReport(fileCover.absolutePath) - // Setup Main Datasource - val dataSource: JRBeanCollectionDataSource = JRBeanCollectionDataSource(mutableListOf(projectReportCollection)) - // Setup Parameter & add Sub-datasets - val parameters = HashMap() - // Fill Reports - val jasperPrintCover: JasperPrint = JasperFillManager.fillReport(jasperReportCover, parameters, dataSource) - // Create File - var finalFile: File = File(reportDefaultPdf) - return if (reportFormat.equals("pdf")) { - JasperExportManager.exportReportToPdfFile(jasperPrintCover, reportDestination + "A_Cover.pdf") - finalFile = File(reportDestination + "A_Cover.pdf") - finalFile - } else { - // ToDo: Implement different report formats - finalFile + val fileCoverStream = javaClass.getResourceAsStream(reportCoverDesignTemplate) + // Open file stream + fileCoverStream.use { stream -> + val inputStream = ByteArrayInputStream(stream.readAllBytes()) + // Compile Jasper Reports + val jasperReportCover: JasperReport = JasperCompileManager.compileReport(inputStream) + // Setup Main Datasource + val dataSource: JRBeanCollectionDataSource = + JRBeanCollectionDataSource(mutableListOf(projectReportCollection)) + // Setup Parameter & add Sub-datasets + val parameters = HashMap() + parameters["CDATA_WATERMARK"] = waterMarkPath + parameters["CDATA_C4POCoverBackground"] = coverBackgroundPath + // Fill Reports + val jasperPrintCover: JasperPrint = JasperFillManager.fillReport(jasperReportCover, parameters, dataSource) + // Create File + var finalFile: ByteArray = javaClass.getResourceAsStream(reportDefaultPdfPropertyPath).readAllBytes() + // Export Report + return if (reportFormat.equals("pdf")) { + finalFile = JasperExportManager.exportReportToPdf(jasperPrintCover) + finalFile + } else { + // ToDo: Implement different report formats + finalFile + } } } - private fun createTableOfContent(projectReportCollection: ProjectReport, reportFormat: String): File { + private fun createTableOfContent(projectReportCollection: ProjectReport, reportFormat: String): ByteArray { // Load Jasper Files - val fileContent: File = ResourceUtils.getFile(reportContentDesignTemplate) - // Compile Jasper Reports - val jasperReportContent: JasperReport = JasperCompileManager.compileReport(fileContent.absolutePath) - // Setup Sub-dataset for Table of Content generation - val projectPentestReportDataSource: JRBeanCollectionDataSource = - JRBeanCollectionDataSource(projectReportCollection.projectPentestReport) - // Setup Parameter & add Sub-datasets - val parameters = HashMap() - parameters["ProjectPentestReportDataSource"] = projectPentestReportDataSource - // Fill Reports - val jasperPrintContent: JasperPrint = - JasperFillManager.fillReport(jasperReportContent, parameters, JREmptyDataSource()) - // Create File - var finalFile: File = File(reportDefaultPdf) - return if (reportFormat.equals("pdf")) { - JasperExportManager.exportReportToPdfFile(jasperPrintContent, reportDestination + "B_Content.pdf") - finalFile = File(reportDestination + "B_Content.pdf") - finalFile - } else { - // ToDo: Implement different report formats - finalFile + val fileContentStream = javaClass.getResourceAsStream(reportContentDesignTemplate) + // Open file stream + fileContentStream.use { stream -> + val inputStream = ByteArrayInputStream(stream.readAllBytes()) + // Compile Jasper Reports + val jasperReportContent: JasperReport = JasperCompileManager.compileReport(inputStream) + // Setup Sub-dataset for Table of Content generation + val projectPentestReportDataSource: JRBeanCollectionDataSource = + JRBeanCollectionDataSource(projectReportCollection.projectPentestReport) + // Setup Parameter & add Sub-datasets + val parameters = HashMap() + parameters["ProjectPentestReportDataSource"] = projectPentestReportDataSource + parameters["CDATA_WATERMARK"] = waterMarkPath + // Fill Reports + val jasperPrintContent: JasperPrint = + JasperFillManager.fillReport(jasperReportContent, parameters, JREmptyDataSource()) + // Create File + var finalFile: ByteArray = javaClass.getResourceAsStream(reportDefaultPdfPropertyPath).readAllBytes() + // Export Report + return if (reportFormat.equals("pdf")) { + finalFile = JasperExportManager.exportReportToPdf(jasperPrintContent) + finalFile + } else { + // ToDo: Implement different report formats + finalFile + } } } - private fun createStateOfConfidentiality(projectReportCollection: ProjectReport, reportFormat: String): File { + private fun createStateOfConfidentiality(projectReportCollection: ProjectReport, reportFormat: String): ByteArray { // Load Jasper Files - val fileContent: File = ResourceUtils.getFile(reportStateOfConfidentialityDesignTemplate) - // Compile Jasper Reports - val jasperReportContent: JasperReport = JasperCompileManager.compileReport(fileContent.absolutePath) - // Setup Main Datasource - val dataSource: JRBeanCollectionDataSource = JRBeanCollectionDataSource(mutableListOf(projectReportCollection)) - // Setup Parameter & add Sub-datasets - val parameters = HashMap() - // Fill Reports - val jasperPrintContent: JasperPrint = JasperFillManager.fillReport(jasperReportContent, parameters, dataSource) - // Create File - var finalFile: File = File(reportDefaultPdf) - return if (reportFormat.equals("pdf")) { - JasperExportManager.exportReportToPdfFile( - jasperPrintContent, - reportDestination + "C_StateOfConfidentiality.pdf" + val fileStateOfConfidentialityStream = javaClass.getResourceAsStream(reportStateOfConfidentialityDesignTemplate) + // Open file stream + fileStateOfConfidentialityStream.use { stream -> + val inputStream = ByteArrayInputStream(stream.readAllBytes()) + // Compile Jasper Reports + val jasperReportContent: JasperReport = JasperCompileManager.compileReport(inputStream) + // Setup Main Datasource + val dataSource: JRBeanCollectionDataSource = + JRBeanCollectionDataSource(mutableListOf(projectReportCollection)) + // Setup Parameter & add Sub-datasets + val parameters = HashMap() + parameters["CDATA_WATERMARK"] = waterMarkPath + // Fill Reports + val jasperPrintStateOfConfidentiality: JasperPrint = + JasperFillManager.fillReport(jasperReportContent, parameters, dataSource) + // Create File + var finalFile: ByteArray = javaClass.getResourceAsStream(reportDefaultPdfPropertyPath).readAllBytes() + return if (reportFormat.equals("pdf")) { + finalFile = JasperExportManager.exportReportToPdf(jasperPrintStateOfConfidentiality) + finalFile + } else { + // ToDo: Implement different report formats + finalFile + } + } + } + + private fun createExecutiveSummary(projectReportCollection: ProjectReport, reportFormat: String): ByteArray { + // Load Jasper Files + val fileExecutiveSummaryStream = javaClass.getResourceAsStream(reportExecutiveSummaryDesignTemplate) + // Open file stream + fileExecutiveSummaryStream.use { stream -> + val inputStream = ByteArrayInputStream(stream.readAllBytes()) + // Compile Jasper Reports + val jasperReportContent: JasperReport = JasperCompileManager.compileReport(inputStream) + // Setup Main Datasource + val dataSource: JRBeanCollectionDataSource = + JRBeanCollectionDataSource(mutableListOf(projectReportCollection)) + // Setup Sub-dataset for pentest evaluation pie charts + // Setup CategoryPieDataSet for each Category + val categoryFindings: MutableList = mutableListOf( + CategoryPieData("INFORMATION_GATHERING", 0), + CategoryPieData("CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING", 0), + CategoryPieData("IDENTITY_MANAGEMENT_TESTING", 0), + CategoryPieData("AUTHENTICATION_TESTING", 0), + CategoryPieData("AUTHORIZATION_TESTING", 0), + CategoryPieData("SESSION_MANAGEMENT_TESTING", 0), + CategoryPieData("INPUT_VALIDATION_TESTING", 0), + CategoryPieData("ERROR_HANDLING", 0), + CategoryPieData("CRYPTOGRAPHY", 0), + CategoryPieData("BUSINESS_LOGIC_TESTING", 0), + CategoryPieData("CLIENT_SIDE_TESTING", 0) ) - finalFile = File(reportDestination + "C_StateOfConfidentiality.pdf") - finalFile - } else { - // ToDo: Implement different report formats - finalFile - } - } - - private fun createExecutiveSummary(projectReportCollection: ProjectReport, reportFormat: String): File { - // Load Jasper Files - val fileContent: File = ResourceUtils.getFile(reportExecutiveSummaryDesignTemplate) - // Compile Jasper Reports - val jasperReportContent: JasperReport = JasperCompileManager.compileReport(fileContent.absolutePath) - // Setup Main Datasource - val dataSource: JRBeanCollectionDataSource = JRBeanCollectionDataSource(mutableListOf(projectReportCollection)) - // Setup Sub-dataset for pentest evaluation pie charts - // Setup CategoryPieDataSet for each Category - val categoryFindings: MutableList = mutableListOf( - CategoryPieData("INFORMATION_GATHERING", 0), - CategoryPieData("CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING", 0), - CategoryPieData("IDENTITY_MANAGEMENT_TESTING", 0), - CategoryPieData("AUTHENTICATION_TESTING", 0), - CategoryPieData("AUTHORIZATION_TESTING", 0), - CategoryPieData("SESSION_MANAGEMENT_TESTING", 0), - CategoryPieData("INPUT_VALIDATION_TESTING", 0), - CategoryPieData("ERROR_HANDLING", 0), - CategoryPieData("CRYPTOGRAPHY", 0), - CategoryPieData("BUSINESS_LOGIC_TESTING", 0), - CategoryPieData("CLIENT_SIDE_TESTING", 0) - ) - // Fill data for CategoryPieDataSet - for (i in 0 until projectReportCollection.projectPentestReport.size) { - when (projectReportCollection.projectPentestReport[i].category) { - "INFORMATION_GATHERING" -> { - categoryFindings[0].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - } - - "CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING" -> { - categoryFindings[1].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - } - - "IDENTITY_MANAGEMENT_TESTING" -> { - categoryFindings[2].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - } - - "AUTHENTICATION_TESTING" -> { - categoryFindings[3].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - } - - "AUTHORIZATION_TESTING" -> { - categoryFindings[4].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - } - - "SESSION_MANAGEMENT_TESTING" -> { - categoryFindings[5].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - } - - "INPUT_VALIDATION_TESTING" -> { - categoryFindings[6].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - } - - "ERROR_HANDLING" -> { - categoryFindings[7].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - } - - "CRYPTOGRAPHY" -> { - categoryFindings[8].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - } - - "BUSINESS_LOGIC_TESTING" -> { - categoryFindings[9].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - 1 - } - - "CLIENT_SIDE_TESTING" -> { - categoryFindings[10].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - 1 - } - - else -> { - categoryFindings.add( - CategoryPieData( - "UNKNOWN_CATEGORY", - projectReportCollection.projectPentestReport[i].findings.size - ) - ) - } - } - } - val categoryFindingsDataSource: JRBeanCollectionDataSource = JRBeanCollectionDataSource(categoryFindings) - // Setup SeverityPieData for each Severity - val severityFindings: MutableList = mutableListOf( - SeverityPieData("LOW", 0), - SeverityPieData("MEDIUM", 0), - SeverityPieData("HIGH", 0), - SeverityPieData("CRITICAL", 0) - ) - // Fill data for SeverityPieData - for (i in 0 until projectReportCollection.projectPentestReport.size) { - for (j in 0 until projectReportCollection.projectPentestReport[i].findings.size) { - when (projectReportCollection.projectPentestReport[i].findings[j].severity) { - "LOW" -> { - severityFindings[0].numberOfFindings += 1 + // Fill data for CategoryPieDataSet + for (i in 0 until projectReportCollection.projectPentestReport.size) { + when (projectReportCollection.projectPentestReport[i].category) { + "INFORMATION_GATHERING" -> { + categoryFindings[0].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size } - "MEDIUM" -> { - severityFindings[1].numberOfFindings += 1 + "CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING" -> { + categoryFindings[1].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size } - "HIGH" -> { - severityFindings[2].numberOfFindings += 1 + "IDENTITY_MANAGEMENT_TESTING" -> { + categoryFindings[2].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size } - "CRITICAL" -> { - severityFindings[3].numberOfFindings += 1 + "AUTHENTICATION_TESTING" -> { + categoryFindings[3].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size + } + + "AUTHORIZATION_TESTING" -> { + categoryFindings[4].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size + } + + "SESSION_MANAGEMENT_TESTING" -> { + categoryFindings[5].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size + } + + "INPUT_VALIDATION_TESTING" -> { + categoryFindings[6].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size + } + + "ERROR_HANDLING" -> { + categoryFindings[7].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size + } + + "CRYPTOGRAPHY" -> { + categoryFindings[8].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size + } + + "BUSINESS_LOGIC_TESTING" -> { + categoryFindings[9].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - 1 + } + + "CLIENT_SIDE_TESTING" -> { + categoryFindings[10].numberOfFindings += projectReportCollection.projectPentestReport[i].findings.size - 1 } else -> { - severityFindings.add( - SeverityPieData( - "UNKNOWN_SEVERITY", + categoryFindings.add( + CategoryPieData( + "UNKNOWN_CATEGORY", projectReportCollection.projectPentestReport[i].findings.size ) ) } } } - } - val severityFindingsDataSource: JRBeanCollectionDataSource = JRBeanCollectionDataSource(severityFindings) - // Setup Parameter & add Sub-datasets - val parameters = HashMap() - parameters["CategoryFindingsPieChartDataSource"] = categoryFindingsDataSource - parameters["SeverityFindingsPieChartDataSource"] = severityFindingsDataSource - // Fill Reports - val jasperPrintContent: JasperPrint = JasperFillManager.fillReport(jasperReportContent, parameters, dataSource) - // Create File - var finalFile: File = File(reportDefaultPdf) - return if (reportFormat.equals("pdf")) { - JasperExportManager.exportReportToPdfFile(jasperPrintContent, reportDestination + "D_ExecutiveSummary.pdf") - finalFile = File(reportDestination + "D_ExecutiveSummary.pdf") - finalFile - } else { - // ToDo: Implement different report formats - finalFile + val categoryFindingsDataSource: JRBeanCollectionDataSource = JRBeanCollectionDataSource(categoryFindings) + // Setup SeverityPieData for each Severity + val severityFindings: MutableList = mutableListOf( + SeverityPieData("LOW", 0), + SeverityPieData("MEDIUM", 0), + SeverityPieData("HIGH", 0), + SeverityPieData("CRITICAL", 0) + ) + // Fill data for SeverityPieData + for (i in 0 until projectReportCollection.projectPentestReport.size) { + for (j in 0 until projectReportCollection.projectPentestReport[i].findings.size) { + when (projectReportCollection.projectPentestReport[i].findings[j].severity) { + "LOW" -> { + severityFindings[0].numberOfFindings += 1 + } + + "MEDIUM" -> { + severityFindings[1].numberOfFindings += 1 + } + + "HIGH" -> { + severityFindings[2].numberOfFindings += 1 + } + + "CRITICAL" -> { + severityFindings[3].numberOfFindings += 1 + } + + else -> { + severityFindings.add( + SeverityPieData( + "UNKNOWN_SEVERITY", + projectReportCollection.projectPentestReport[i].findings.size + ) + ) + } + } + } + } + val severityFindingsDataSource: JRBeanCollectionDataSource = JRBeanCollectionDataSource(severityFindings) + // Setup Parameter & add Sub-datasets + val parameters = HashMap() + parameters["CategoryFindingsPieChartDataSource"] = categoryFindingsDataSource + parameters["SeverityFindingsPieChartDataSource"] = severityFindingsDataSource + parameters["CDATA_WATERMARK"] = waterMarkPath + // Fill Reports + val jasperPrintExecutiveSummary: JasperPrint = + JasperFillManager.fillReport(jasperReportContent, parameters, dataSource) + // Create File + var finalFile: ByteArray = javaClass.getResourceAsStream(reportDefaultPdfPropertyPath).readAllBytes() + return if (reportFormat.equals("pdf")) { + finalFile = JasperExportManager.exportReportToPdf(jasperPrintExecutiveSummary) + finalFile + } else { + // ToDo: Implement different report formats + finalFile + } } } - private fun createPentestReports(projectReportCollection: ProjectReport, reportFormat: String): List { + private fun createPentestReports(projectReportCollection: ProjectReport, reportFormat: String): List { // Create List of Files - var finalFiles: List = emptyList() + var finalFiles: List = emptyList() // Load Jasper Files - val filePentestsFindingsAndComments: File = ResourceUtils.getFile(reportPentestsFindingsAndCommentsDesignTemplate) - val filePentestsFindingsOnly: File = ResourceUtils.getFile(reportPentestsFindingsOnlyDesignTemplate) - val filePentestsCommentsOnly: File = ResourceUtils.getFile(reportPentestsCommentsOnlyDesignTemplate) - // Compile Jasper Reports - val jasperReportPentestsFindingsAndComments: JasperReport = JasperCompileManager.compileReport(filePentestsFindingsAndComments.absolutePath) - val jasperReportPentestsFindingsOnly: JasperReport = JasperCompileManager.compileReport(filePentestsFindingsOnly.absolutePath) - val jasperReportPentestsCommentsOnly: JasperReport = JasperCompileManager.compileReport(filePentestsCommentsOnly.absolutePath) - // Create pentestReport content for every objective - for (i in 0 until projectReportCollection.projectPentestReport.size) { - val projectSinglePentestReportDataSource: JRBeanCollectionDataSource = - JRBeanCollectionDataSource(mutableListOf(projectReportCollection.projectPentestReport[i])) - // Setup Parameter & add Sub-datasets - val parameters = HashMap() - // Setup Sub-dataset for Findings of Pentest - parameters["PentestFindingsDataSource"] = JRBeanCollectionDataSource(projectReportCollection.projectPentestReport[i].findings) - // Setup Sub-dataset for Comments of Pentest - parameters["PentestCommentsDataSource"] = JRBeanCollectionDataSource(projectReportCollection.projectPentestReport[i].comments) - // Fill Reports - // Print one report for each objective and merge them together afterwards - val jasperPrintPentests: JasperPrint = if (projectReportCollection.projectPentestReport[i].findings.isEmpty()) { - JasperFillManager.fillReport(jasperReportPentestsCommentsOnly, parameters, projectSinglePentestReportDataSource) - } else if (projectReportCollection.projectPentestReport[i].comments.isEmpty()) { - JasperFillManager.fillReport(jasperReportPentestsFindingsOnly, parameters, projectSinglePentestReportDataSource) - } else { - JasperFillManager.fillReport(jasperReportPentestsFindingsAndComments, parameters, projectSinglePentestReportDataSource) - } - // Create File - var finalFile: File = File(reportDefaultPdf) - if (reportFormat.equals("pdf")) { - JasperExportManager.exportReportToPdfFile( - jasperPrintPentests, - reportDestination + "E" + i.toString() + "_Pentestreport.pdf" - ) - finalFile = File(reportDestination + "E" + i.toString() + "_Pentestreport.pdf") - finalFiles += (finalFile) - } else { - println("NONONO") - // ToDo: Implement different report formats - finalFiles += (finalFile) + val filePentestsFindingsAndCommentsStream = + javaClass.getResourceAsStream(reportPentestsFindingsAndCommentsDesignTemplate) + val filePentestsFindingsOnlyStream = javaClass.getResourceAsStream(reportPentestsFindingsOnlyDesignTemplate) + val filePentestsCommentsOnlyStream = javaClass.getResourceAsStream(reportPentestsCommentsOnlyDesignTemplate) + // Open file stream for findings & comments + filePentestsFindingsAndCommentsStream.use { pentestsFindingsAndCommentsStream -> + val inputFindingsAndCommentsStream = ByteArrayInputStream(pentestsFindingsAndCommentsStream.readAllBytes()) + // Setup Jasper Report + val jasperReportPentestsFindingsAndComments = + JasperCompileManager.compileReport(inputFindingsAndCommentsStream) + // Open file stream for findings only + filePentestsFindingsOnlyStream.use { pentestsFindingsOnlyStream -> + val inputFindingsOnlyStream = ByteArrayInputStream(pentestsFindingsOnlyStream.readAllBytes()) + // Setup Jasper Report + val jasperReportPentestsFindingsOnly: JasperReport = + JasperCompileManager.compileReport(inputFindingsOnlyStream) + // Open file stream for comments only + filePentestsCommentsOnlyStream.use { pentestsCommentsOnlyStream -> + val inputCommentsOnlyStream = ByteArrayInputStream(pentestsCommentsOnlyStream.readAllBytes()) + // Setup Jasper Report + val jasperReportPentestsCommentsOnly: JasperReport = + JasperCompileManager.compileReport(inputCommentsOnlyStream) + // Create pentestReport content for every objective + for (i in 0 until projectReportCollection.projectPentestReport.size) { + val projectSinglePentestReportDataSource: JRBeanCollectionDataSource = + JRBeanCollectionDataSource(mutableListOf(projectReportCollection.projectPentestReport[i])) + // Setup Parameter & add Sub-datasets + val parameters = HashMap() + // Setup Sub-dataset for Findings of Pentest + parameters["PentestFindingsDataSource"] = + JRBeanCollectionDataSource(projectReportCollection.projectPentestReport[i].findings) + // Setup Sub-dataset for Comments of Pentest + parameters["PentestCommentsDataSource"] = + JRBeanCollectionDataSource(projectReportCollection.projectPentestReport[i].comments) + parameters["CDATA_WATERMARK"] = waterMarkPath + parameters["CDATA_FindingsSubreport"] = findingsSubreportPath + parameters["CDATA_CommentsSubreport"] = commentsSubreportPath + // Fill Reports + // Print one report for each objective and merge them together afterwards + val jasperPrintPentests: JasperPrint = + if (projectReportCollection.projectPentestReport[i].findings.isEmpty()) { + JasperFillManager.fillReport( + jasperReportPentestsCommentsOnly, + parameters, + projectSinglePentestReportDataSource + ) + } else if (projectReportCollection.projectPentestReport[i].comments.isEmpty()) { + JasperFillManager.fillReport( + jasperReportPentestsFindingsOnly, + parameters, + projectSinglePentestReportDataSource + ) + } else { + JasperFillManager.fillReport( + jasperReportPentestsFindingsAndComments, + parameters, + projectSinglePentestReportDataSource + ) + } + // Create File + val finalFile: ByteArray = + javaClass.getResourceAsStream(reportDefaultPdfPropertyPath).readAllBytes() + // var finalFile: ByteArray = javaClass.getResourceAsStream(reportDefaultPdfProperty).readAllBytes() + if (reportFormat.equals("pdf")) { + finalFiles += JasperExportManager.exportReportToPdf(jasperPrintPentests) + } else { + // ToDo: Implement different report formats + finalFiles += (finalFile) + } + } + } } } return finalFiles } - private fun createAppendencies(reportFormat: String): File { + private fun createAppendencies(reportFormat: String): ByteArray { // Load Jasper Files - val fileCover: File = ResourceUtils.getFile(reportAppendenciesDesignTemplate) - // Compile Jasper Reports - val jasperReportCover: JasperReport = JasperCompileManager.compileReport(fileCover.absolutePath) - // Setup Parameter & add Sub-datasets - val parameters = HashMap() - parameters["SeverityRatingDefinition"] = JREmptyDataSource() - // Fill Reports - val jasperPrintCover: JasperPrint = - JasperFillManager.fillReport(jasperReportCover, parameters, JREmptyDataSource()) - // Create File - var finalFile: File = File(reportDefaultPdf) - return if (reportFormat.equals("pdf")) { - JasperExportManager.exportReportToPdfFile(jasperPrintCover, reportDestination + "F_Appendencies.pdf") - finalFile = File(reportDestination + "F_Appendencies.pdf") - finalFile - } else { - // ToDo: Implement different report formats - finalFile + val fileAppendenciesStream = javaClass.getResourceAsStream(reportAppendenciesDesignTemplate) + // Open file stream + fileAppendenciesStream.use { stream -> + val inputStream = ByteArrayInputStream(stream.readAllBytes()) + // Compile Jasper Reports + val jasperReportCover: JasperReport = JasperCompileManager.compileReport(inputStream) + // Setup Parameter & add Sub-datasets + val parameters = HashMap() + parameters["SeverityRatingDefinition"] = JREmptyDataSource() + parameters["CDATA_WATERMARK"] = waterMarkPath + parameters["CDATA_SeverityRatingTable"] = severityRatingTablePath + // Fill Reports + val jasperPrintAppendencies: JasperPrint = + JasperFillManager.fillReport(jasperReportCover, parameters, JREmptyDataSource()) + // Create File + var finalFile: ByteArray = javaClass.getResourceAsStream(reportDefaultPdfPropertyPath).readAllBytes() + return if (reportFormat.equals("pdf")) { + finalFile = JasperExportManager.exportReportToPdf(jasperPrintAppendencies) + finalFile + } else { + // ToDo: Implement different report formats + finalFile + } } } } \ No newline at end of file diff --git a/security-c4po-reporting/src/main/resources/application-COMPOSE.properties b/security-c4po-reporting/src/main/resources/application-COMPOSE.properties index d48b8b4..bd86a5c 100644 --- a/security-c4po-reporting/src/main/resources/application-COMPOSE.properties +++ b/security-c4po-reporting/src/main/resources/application-COMPOSE.properties @@ -3,3 +3,18 @@ spring.security.oauth2.resourceserver.jwt.issuer-uri=http://c4po-keycloak:8080/a keycloakhost=c4po-keycloak keycloak.client.url=http://c4po-keycloak:8080 keycloak.client.realm.path=auth/realms/c4po_realm_local/ + +## C4PO_ApiService ## +api.client.url=http://c4po-api:8443/ +api.client.projects.path=projects +api.client.pentests.path=pentests + +## Jasper ## +# Ressource variables for jrxml files # +CDATA_WATERMARK=BOOT-INF/classes/jasper/Watermark.png +CDATA_C4POCoverBackground=BOOT-INF/classes/jasper/C4POCoverBackground#1.jpeg +# Subreports # +CDATA_FindingsSubreport=BOOT-INF/classes/jasper/subReports/FindingsSubreport.jasper +CDATA_CommentsSubreport=BOOT-INF/classes/jasper/subReports/CommentsSubreport.jasper +CDATA_SeverityRatingTable=BOOT-INF/classes/jasper/subReports/SeverityRatingTableSubreport.jasper + diff --git a/security-c4po-reporting/src/main/resources/application.properties b/security-c4po-reporting/src/main/resources/application.properties index 33feca7..884b849 100644 --- a/security-c4po-reporting/src/main/resources/application.properties +++ b/security-c4po-reporting/src/main/resources/application.properties @@ -25,4 +25,24 @@ keycloak.client.realm.path=auth/realms/c4po_realm_local/ ## Total number of pentests listet in the OWASP testing guide ## https://owasp.org/www-project-web-security-testing-guide/assets/archive/OWASP_Testing_Guide_v4.pdf -owasp.web.pentests=95 \ No newline at end of file +# ToDo: Disabled objectives are not excluded as of now +owasp.web.pentests=95 + +## Jasper ## +reportCoverDesignTemplate=/jasper/reports/c4po_cover.jrxml +reportContentDesignTemplate=/jasper/reports/c4po_content.jrxml +reportStateOfConfidentialityDesignTemplate=/jasper/reports/c4po_state_of_confidentiality.jrxml +reportExecutiveSummaryDesignTemplate=/jasper/reports/c4po_executive_summary.jrxml +reportPentestsFindingsAndCommentsDesignTemplate=/jasper/reports/c4po_pentests_findings_and_comments.jrxml +reportPentestsFindingsOnlyDesignTemplate=/jasper/reports/c4po_pentests_findings_only.jrxml +reportPentestsCommentsOnlyDesignTemplate=/jasper/reports/c4po_pentests_comments_only.jrxml +reportAppendenciesDesignTemplate=/jasper/reports/c4po_appendencies.jrxml +# Path to default pdf file # +reportDefaultPdf=/jasper/DEFAULT.pdf +# Ressource variables for jrxml files # +CDATA_WATERMARK=./src/main/resources/jasper/Watermark.png +CDATA_C4POCoverBackground=./src/main/resources/jasper/C4POCoverBackground#1.jpeg +# Subreports # +CDATA_FindingsSubreport=./src/main/resources/jasper/subReports/FindingsSubreport.jasper +CDATA_CommentsSubreport=./src/main/resources/jasper/subReports/CommentsSubreport.jasper +CDATA_SeverityRatingTable=./src/main/resources/jasper/subReports/SeverityRatingTableSubreport.jasper \ No newline at end of file diff --git a/security-c4po-reporting/src/main/resources/jasper/reports/c4po_appendencies.jrxml b/security-c4po-reporting/src/main/resources/jasper/reports/c4po_appendencies.jrxml index 6e67357..2205b2c 100644 --- a/security-c4po-reporting/src/main/resources/jasper/reports/c4po_appendencies.jrxml +++ b/security-c4po-reporting/src/main/resources/jasper/reports/c4po_appendencies.jrxml @@ -2,6 +2,10 @@ + + + + @@ -24,7 +28,7 @@ - + @@ -54,7 +58,7 @@ - + diff --git a/security-c4po-reporting/src/main/resources/jasper/reports/c4po_content.jrxml b/security-c4po-reporting/src/main/resources/jasper/reports/c4po_content.jrxml index 79dd6ea..45ca269 100644 --- a/security-c4po-reporting/src/main/resources/jasper/reports/c4po_content.jrxml +++ b/security-c4po-reporting/src/main/resources/jasper/reports/c4po_content.jrxml @@ -2,6 +2,8 @@ + +