Skip to content

Commit

Permalink
supporting changes for #435, #436, #437, #438, #439, and #440
Browse files Browse the repository at this point in the history
  • Loading branch information
vscheuber committed Aug 13, 2024
1 parent e5040dd commit 0a6ad55
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 89 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- \#435 - Support for Advanced Identitty Cloud Environment Content Security Policy API
- \#436 - Support for Advanced Identitty Cloud Environment Cookie Domains API
- \#437 - Support for Advanced Identitty Cloud Environment Custom Domains API
- \#438 - Support for Advanced Identitty Cloud Environment Federation Enforcement API
- \#439 - Support for Advanced Identitty Cloud Environment Release API
- \#440 - Support for Advanced Identitty Cloud Environment SSO Cookie API

### Fixed

- \#448: Frodo Library now accepts an additional optional boolean param `wait`, which if provided delays the response until an OSGi service event confirms the change has been consumed by the corresponding service or the request times out, to the following `frodo.idm.config` functions:

- createConfigEntity
- updateConfigEntity

## [2.0.2] - 2024-08-06

### Added
Expand Down
35 changes: 31 additions & 4 deletions src/lib/FrodoLib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,23 @@ import AdminFederationOps, {
import EnvCertificatesOps, {
EnvCertificate,
} from '../ops/cloud/EnvCertificatesOps';
import EnvContentSecurityOps, {
EnvContentSecurityPolicy,
} from '../ops/cloud/EnvContentSecurityPolicyOps';
import EnvCookieDomainsOps, {
EnvCookieDomains,
} from '../ops/cloud/EnvCookieDomainsOps';
import EnvCSRsOps, { EnvCSR } from '../ops/cloud/EnvCSRsOps';
import EnvCustomDomainsOps, {
EnvCustomDomains,
} from '../ops/cloud/EnvCustomDomainsOps';
import EnvFederationEnforcementOps, {
EnvFederationEnforcement,
} from '../ops/cloud/EnvFederationEnforcementOps';
import EnvReleaseOps, { EnvRelease } from '../ops/cloud/EnvReleaseOps';
import EnvSSOCookieConfigOps, {
EnvSSOCookieConfig,
} from '../ops/cloud/EnvSSOCookieConfigOps';
import EsvCountOps, { EsvCount } from '../ops/cloud/EsvCountOps';
import FeatureOps, { Feature } from '../ops/cloud/FeatureOps';
import LogOps, { Log } from '../ops/cloud/LogOps';
Expand Down Expand Up @@ -93,10 +109,15 @@ export type Frodo = {

cloud: {
adminFed: AdminFederation;
env: {
cert: EnvCertificate;
csr: EnvCSR;
};
env: EnvContentSecurityPolicy &
EnvCookieDomains &
EnvCustomDomains &
EnvFederationEnforcement &
EnvRelease &
EnvSSOCookieConfig & {
cert: EnvCertificate;
csr: EnvCSR;
};
esvCount: EsvCount;
feature: Feature;
log: Log;
Expand Down Expand Up @@ -242,6 +263,12 @@ const FrodoLib = (config: StateInterface = {}): Frodo => {
cloud: {
adminFed: AdminFederationOps(state),
env: {
...EnvContentSecurityOps(state),
...EnvCookieDomainsOps(state),
...EnvCustomDomainsOps(state),
...EnvFederationEnforcementOps(state),
...EnvReleaseOps(state),
...EnvSSOCookieConfigOps(state),
cert: EnvCertificatesOps(state),
csr: EnvCSRsOps(state),
},
Expand Down
38 changes: 29 additions & 9 deletions src/ops/AuthenticateOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,29 @@ export default (state: State): Authenticate => {
const adminClientPassword = 'doesnotmatter';
const redirectUrlTemplate = '/platform/appAuthHelperRedirect.html';

const cloudIdmAdminScopes = 'openid fr:idm:* fr:idc:esv:*';
const forgeopsIdmAdminScopes = 'openid fr:idm:*';
const serviceAccountDefaultScopes = SERVICE_ACCOUNT_DEFAULT_SCOPES.join(' '); //'fr:am:* fr:idm:* fr:idc:esv:*';
const s = Constants.AVAILABLE_SCOPES;
const CLOUD_ADMIN_DEFAULT_SCOPES: string[] = [
s.AnalyticsFullScope,
s.AutoAccessFullScope,
s.CertificateFullScope,
s.ContentSecurityPolicyFullScope,
s.CookieDomainsFullScope,
s.CustomDomainFullScope,
s.ESVFullScope,
s.FederationEnforcementFullScope,
s.IdmFullScope,
s.IGAFullScope,
s.OpenIdScope,
s.PromotionScope,
s.ReleaseFullScope,
s.SSOCookieFullScope,
s.WafFullScope,
];
const FORGEOPS_ADMIN_DEFAULT_SCOPES: string[] = [s.IdmFullScope, s.OpenIdScope];

const cloudAdminScopes = CLOUD_ADMIN_DEFAULT_SCOPES.join(' ');
const forgeopsAdminScopes = FORGEOPS_ADMIN_DEFAULT_SCOPES.join(' ');
const serviceAccountDefaultScopes = SERVICE_ACCOUNT_DEFAULT_SCOPES.join(' ');

const fidcClientId = 'idmAdminClient';
const forgeopsClientId = 'idm-admin-ui';
Expand All @@ -120,7 +140,7 @@ let adminClientId = fidcClientId;
* @param {State} state library state
* @returns {string} cookie name
*/
async function determineCookieName(state: State) {
async function determineCookieName(state: State): Promise<string> {
const data = await getServerInfo({ state });
debugMessage({
message: `AuthenticateOps.determineCookieName: cookieName=${data.cookieName}`,
Expand Down Expand Up @@ -309,7 +329,7 @@ async function determineDeploymentType(state: State): Promise<string> {
[state.getCookieName()]: state.getCookieValue(),
},
};
let bodyFormData = `redirect_uri=${redirectURL}&scope=${cloudIdmAdminScopes}&response_type=code&client_id=${fidcClientId}&csrf=${cookieValue}&decision=allow&code_challenge=${challenge}&code_challenge_method=${challengeMethod}`;
let bodyFormData = `redirect_uri=${redirectURL}&scope=${cloudAdminScopes}&response_type=code&client_id=${fidcClientId}&csrf=${cookieValue}&decision=allow&code_challenge=${challenge}&code_challenge_method=${challengeMethod}`;

deploymentType = Constants.CLASSIC_DEPLOYMENT_TYPE_KEY;
try {
Expand All @@ -332,7 +352,7 @@ async function determineDeploymentType(state: State): Promise<string> {
deploymentType = Constants.CLOUD_DEPLOYMENT_TYPE_KEY;
} else {
try {
bodyFormData = `redirect_uri=${redirectURL}&scope=${forgeopsIdmAdminScopes}&response_type=code&client_id=${forgeopsClientId}&csrf=${state.getCookieValue()}&decision=allow&code_challenge=${challenge}&code_challenge_method=${challengeMethod}`;
bodyFormData = `redirect_uri=${redirectURL}&scope=${forgeopsAdminScopes}&response_type=code&client_id=${forgeopsClientId}&csrf=${state.getCookieValue()}&decision=allow&code_challenge=${challenge}&code_challenge_method=${challengeMethod}`;
await authorize({
amBaseUrl: state.getHost(),
data: bodyFormData,
Expand Down Expand Up @@ -524,8 +544,8 @@ async function getAuthCode(
try {
const bodyFormData = `redirect_uri=${redirectURL}&scope=${
state.getDeploymentType() === Constants.CLOUD_DEPLOYMENT_TYPE_KEY
? cloudIdmAdminScopes
: forgeopsIdmAdminScopes
? cloudAdminScopes
: forgeopsAdminScopes
}&response_type=code&client_id=${adminClientId}&csrf=${state.getCookieValue()}&decision=allow&code_challenge=${codeChallenge}&code_challenge_method=${codeChallengeMethod}`;
const config = {
headers: {
Expand Down Expand Up @@ -934,7 +954,7 @@ export type Tokens = {
* @returns {Promise<Tokens>} object containing the tokens
*/
export async function getTokens({
forceLoginAsUser = false,
forceLoginAsUser = process.env.FRODO_FORCE_LOGIN_AS_USER ? true : false,
autoRefresh = true,
types = Constants.DEPLOYMENT_TYPES,
callbackHandler = null,
Expand Down
111 changes: 36 additions & 75 deletions src/ops/cloud/ServiceAccountOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
createManagedObject,
getManagedObject,
} from '../../api/ManagedObjectApi';
import Constants from '../../shared/Constants';
import { State } from '../../shared/State';
import { debugMessage } from '../../utils/Console';
import { FrodoError } from '../FrodoError';
Expand Down Expand Up @@ -88,86 +89,46 @@ export default (state: State): ServiceAccount => {

const moType = 'svcacct';

// Scopes
const scopes = {
OpenIdScope: 'openid',
ProfileScope: 'profile',
AmFullScope: 'fr:am:*',
IdmFullScope: 'fr:idm:*',
AutoAccessFullScope: 'fr:autoaccess:*',
IGAFullScope: 'fr:iga:*',
AnalyticsFullScope: 'fr:idc:analytics:*',

// AMIntrospectRealmTokenScope lets you introspect scopes _from the same realm_, there is a separate scope to introspect tokens from _all_ realms
AMIntrospectRealmTokenScope: 'am-introspect-all-tokens',

// Special AM scopes (used by resource servers)
AMIntrospectAllTokens: 'am-introspect-all-tokens',
AMIntrospectAllTokensAnyRealm: 'am-introspect-all-tokens-any-realm',

// Certificate scopes
CertificateFullScope: 'fr:idc:certificate:*',
CertificateReadScope: 'fr:idc:certificate:read',

// ESV API scopes
ESVFullScope: 'fr:idc:esv:*',
ESVReadScope: 'fr:idc:esv:read',
ESVUpdateScope: 'fr:idc:esv:update',
ESVRestartScope: 'fr:idc:esv:restart',

// Content security policy scopes
ContentSecurityPolicyFullScope: 'fr:idc:content-security-policy:*',

// Federation scopes
FederationFullScope: 'fr:idc:federation:*',
FederationReadScope: 'fr:idc:federation:read',

// Release scopes
ReleaseFullScope: 'fr:idc:release:*',

// SSOCookie scopes
SSOCookieFullScope: 'fr:idc:sso-cookie:*',

// CustomDomainFullScope Custom domain scopes
CustomDomainFullScope: 'fr:idc:custom-domain:*',

// Promotion scopes
PromotionScope: 'fr:idc:promotion:*',
};
const s = Constants.AVAILABLE_SCOPES;

export const SERVICE_ACCOUNT_ALLOWED_SCOPES: string[] = [
scopes.AmFullScope,
scopes.AnalyticsFullScope,
scopes.AutoAccessFullScope,
scopes.CertificateFullScope,
scopes.CertificateReadScope,
scopes.ContentSecurityPolicyFullScope,
scopes.CustomDomainFullScope,
scopes.ESVFullScope,
scopes.ESVReadScope,
scopes.ESVRestartScope,
scopes.ESVUpdateScope,
scopes.IdmFullScope,
scopes.IGAFullScope,
scopes.PromotionScope,
scopes.ReleaseFullScope,
scopes.SSOCookieFullScope,
s.AmFullScope,
s.AnalyticsFullScope,
s.AutoAccessFullScope,
s.CertificateFullScope,
s.CertificateReadScope,
s.ContentSecurityPolicyFullScope,
s.CustomDomainFullScope,
s.ESVFullScope,
s.ESVReadScope,
s.ESVRestartScope,
s.ESVUpdateScope,
s.IdmFullScope,
s.IGAFullScope,
s.PromotionScope,
s.ReleaseFullScope,
s.SSOCookieFullScope,
s.WafFullScope,
s.WafReadScope,
s.WafWriteScope,
s.CookieDomainsFullScope,
];

export const SERVICE_ACCOUNT_DEFAULT_SCOPES: string[] = [
scopes.AmFullScope,
scopes.AnalyticsFullScope,
scopes.AutoAccessFullScope,
scopes.CertificateFullScope,
scopes.CertificateReadScope,
scopes.ContentSecurityPolicyFullScope,
scopes.CustomDomainFullScope,
scopes.ESVFullScope,
scopes.IdmFullScope,
scopes.IGAFullScope,
scopes.PromotionScope,
scopes.ReleaseFullScope,
scopes.SSOCookieFullScope,
s.AmFullScope,
s.AnalyticsFullScope,
s.AutoAccessFullScope,
s.CertificateFullScope,
s.ContentSecurityPolicyFullScope,
s.CookieDomainsFullScope,
s.CustomDomainFullScope,
s.ESVFullScope,
s.IdmFullScope,
s.IGAFullScope,
s.PromotionScope,
s.ReleaseFullScope,
s.SSOCookieFullScope,
s.WafFullScope,
];

export type ServiceAccountType = IdObjectSkeletonInterface & {
Expand Down
57 changes: 57 additions & 0 deletions src/shared/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,62 @@ const FRODO_CONNECTION_PROFILES_PATH_KEY = 'FRODO_CONNECTION_PROFILES_PATH';
const FRODO_MASTER_KEY_PATH_KEY = 'FRODO_MASTER_KEY_PATH';
const FRODO_MASTER_KEY_KEY = 'FRODO_MASTER_KEY';
const FRODO_TOKEN_CACHE_PATH_KEY = 'FRODO_TOKEN_CACHE_PATH';
const AVAILABLE_SCOPES = {
OpenIdScope: 'openid',
ProfileScope: 'profile',
AmFullScope: 'fr:am:*',
IdmFullScope: 'fr:idm:*',
AutoAccessFullScope: 'fr:autoaccess:*',
IGAFullScope: 'fr:iga:*',
AnalyticsFullScope: 'fr:idc:analytics:*',

// AMIntrospectRealmTokenScope lets you introspect scopes _from the same realm_, there is a separate scope to introspect tokens from _all_ realms
AMIntrospectRealmTokenScope: 'am-introspect-all-tokens',

// Special AM scopes (used by resource servers)
AMIntrospectAllTokens: 'am-introspect-all-tokens',
AMIntrospectAllTokensAnyRealm: 'am-introspect-all-tokens-any-realm',

// Certificate scopes
CertificateFullScope: 'fr:idc:certificate:*',
CertificateReadScope: 'fr:idc:certificate:read',

// ESV API scopes
ESVFullScope: 'fr:idc:esv:*',
ESVReadScope: 'fr:idc:esv:read',
ESVUpdateScope: 'fr:idc:esv:update',
ESVRestartScope: 'fr:idc:esv:restart',

// Content security policy scopes
ContentSecurityPolicyFullScope: 'fr:idc:content-security-policy:*',

// Federation scopes
FederationFullScope: 'fr:idc:federation:*',
FederationReadScope: 'fr:idc:federation:read',

// Release scopes
ReleaseFullScope: 'fr:idc:release:*',

// SSOCookie scopes
SSOCookieFullScope: 'fr:idc:sso-cookie:*',

// CustomDomainFullScope Custom domain scopes
CustomDomainFullScope: 'fr:idc:custom-domain:*',

// Promotion scopes
PromotionScope: 'fr:idc:promotion:*',

// WAF scopes
WafFullScope: 'fr:idc:advanced-gateway:*',
WafReadScope: 'fr:idc:advanced-gateway:read',
WafWriteScope: 'fr:idc:advanced-gateway:write',

// Cookie Domains scopes
CookieDomainsFullScope: 'fr:idc:cookie-domain:*',

// Admin Federation Enforcement
FederationEnforcementFullScope: 'fr:idc:federation:*',
};

export default {
DEFAULT_REALM_KEY,
Expand All @@ -46,4 +102,5 @@ export default {
FRODO_MASTER_KEY_PATH_KEY,
FRODO_MASTER_KEY_KEY,
FRODO_TOKEN_CACHE_PATH_KEY,
AVAILABLE_SCOPES,
};
6 changes: 5 additions & 1 deletion src/utils/AutoSetupPolly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ switch (process.env.FRODO_POLLY_MODE) {
// record mock responses from a real env: `npm run test:record`
case 'record': {
setDefaultState();
if (!(await getTokens({ forceLoginAsUser: false, state })))
if (
!(await getTokens({
state,
}))
)
throw new Error(
`Unable to record mock responses from '${state.getHost()}'`
);
Expand Down

0 comments on commit 0a6ad55

Please sign in to comment.