Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add license check for FIPS #181187

Merged
merged 53 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
fd898bc
Adding check when getting the config for the sec plugin to verify FIP…
kc13greiner Jan 9, 2024
392bee9
Merge branch 'main' into feature/add_fips_config
kc13greiner Jan 9, 2024
eff7830
changing fips_mode -> fipsMode
kc13greiner Jan 11, 2024
be473ba
Merge branch 'main' into feature/add_fips_config
kc13greiner Jan 12, 2024
d6f8f5c
Merge branch 'main' into feature/add_fips_config
kc13greiner Jan 16, 2024
eccc9e9
Changing expect to log statement to clarify that it shouldnt throw an…
kc13greiner Jan 22, 2024
ea425ec
Merge branch 'main' into feature/add_fips_config
kc13greiner Jan 24, 2024
d2cc083
Merge branch 'main' into feature/add_fips_config
kc13greiner Feb 2, 2024
b65471c
Merge branch 'main' into feature/add_fips_config
kc13greiner Mar 12, 2024
a0b72e6
Merge branch 'feature/add_fips_config' into feature/fips_license_check
kc13greiner Apr 16, 2024
683531c
Adding license check for FIPS
kc13greiner Apr 18, 2024
03f4b9e
Removing unused line in snapshot
kc13greiner Apr 18, 2024
ff51670
Merge branch 'main' into feature/fips_license_check
kc13greiner Apr 18, 2024
8959fbb
Adding new property
kc13greiner Apr 18, 2024
d50f7c5
Refactoring usage of License in favor of just using SecurityLicense
kc13greiner Apr 23, 2024
b1fa762
Merge branch 'main' into feature/fips_license_check
kc13greiner Apr 23, 2024
9d4d035
Removing console logs
kc13greiner Apr 23, 2024
fd58057
Merge branch 'main' into feature/fips_license_check
kc13greiner Apr 23, 2024
16d7ad8
Fixing jest tests
kc13greiner Apr 23, 2024
2bee3ea
Merge branch 'main' into feature/fips_license_check
kc13greiner Apr 23, 2024
b2fc622
snapshot update
kc13greiner Apr 23, 2024
eb5d11f
Updating snapshots and expected licenses
kc13greiner Apr 23, 2024
b1cab38
Merge branch 'main' into feature/fips_license_check
kc13greiner Apr 23, 2024
abed490
Need to add logic that waits for the license to load, run the start c…
kc13greiner Apr 24, 2024
15ab04b
Merge branch 'main' into feature/fips_license_check
kc13greiner Apr 24, 2024
955cf08
Throwing error instead of exiting
kc13greiner Apr 24, 2024
bc31503
Merge branch 'main' into feature/fips_license_check
kc13greiner Apr 24, 2024
80a3867
Merge branch 'main' into feature/fips_license_check
kc13greiner May 30, 2024
cb93a25
Changing config to experimental and adding updated FIPS docs
kc13greiner May 30, 2024
4816c26
Merge branch 'main' into feature/fips_license_check
kc13greiner May 30, 2024
4daab8c
Removing merge conflict code
kc13greiner May 30, 2024
6672ff9
Merge branch 'main' into feature/fips_license_check
kc13greiner May 30, 2024
27c9d15
Updating jest test snapshot
kc13greiner May 30, 2024
58a9e1b
Merge branch 'main' into feature/fips_license_check
kc13greiner Jun 10, 2024
2126400
Exposing fips setting from security setup
kc13greiner Jun 13, 2024
1b91334
Merge branch 'main' into feature/fips_license_check
kc13greiner Jun 13, 2024
d871efc
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Jun 13, 2024
c37004a
[DOCS] Minor doc edits
lcawl Jun 18, 2024
90050f1
Merge branch 'main' into feature/fips_license_check
lcawl Jun 18, 2024
57c2f36
Exposing fips flag from core
kc13greiner Jun 20, 2024
ff3586a
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Jun 20, 2024
31b7546
Fixing config type and adding tests
kc13greiner Jun 20, 2024
7b1a16a
Merge branch 'main' into feature/fips_license_check
kc13greiner Jun 20, 2024
d5cd54e
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Jun 20, 2024
19244c4
fixing mocks
kc13greiner Jun 20, 2024
d468deb
Merge branch 'main' into feature/fips_license_check
kc13greiner Jun 20, 2024
b7f1de0
Removing tests
kc13greiner Jun 20, 2024
7b7ed01
PR feedback from Pierre
kc13greiner Jun 25, 2024
50015b0
Merge branch 'main' into feature/fips_license_check
kc13greiner Jun 25, 2024
2c11610
Moving FIPS config comparison check to Core > Security Service setup
kc13greiner Jun 26, 2024
fccc836
Merge branch 'main' into feature/fips_license_check
kc13greiner Jun 26, 2024
b82345d
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Jun 26, 2024
33db0d6
Merge branch 'main' into feature/fips_license_check
kc13greiner Jul 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions docs/user/security/fips-140-2.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
[[xpack-security-fips-140-2]]
=== FIPS 140-2
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heya @georgewallace ! Would you or someone on you team be able to take a look at this documentation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heya @elastic/kibana-docs Would someone mind taking a look?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make this page appear in the output, you'll need to add include::fips-140-2.asciidoc[] at the end of the docs/user/security/index.asciidoc file (or in some other navigation file, depending on where it ought to appear in the navigation tree).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the page to the navigation in c37004a. I think it could honestly go in either of these sections: https://www.elastic.co/guide/en/kibana/current/using-kibana-with-security.html or https://www.elastic.co/guide/en/kibana/current/xpack-security.html. I've added it to the latter for now but can easily move if the former makes more sense for this content.


experimental::[]

The Federal Information Processing Standard (FIPS) Publication 140-2, (FIPS PUB 140-2),
titled "Security Requirements for Cryptographic Modules" is a U.S. government computer security standard
used to approve cryptographic modules.

{kib} offers a FIPS 140-2 compliant mode and as such can run in a Node.js environment configured with a FIPS
140-2 compliant OpenSSL3 provider.

To run {kib} in FIPS mode, you must have the appropriate {subscriptions}[subscription].

[IMPORTANT]
============================================================================
The Node bundled with {kib} is not configured for FIPS 140-2. You must configure a FIPS 140-2 compliant OpenSSL3
provider. Consult the Node.js documentation to learn how to configure your environment.
============================================================================

For {kib}, adherence to FIPS 140-2 is ensured by:

* Using FIPS approved / NIST recommended cryptographic algorithms.

* Delegating the implementation of these cryptographic algorithms to a NIST validated cryptographic module
(available via Node.js configured with an OpenSSL3 provider).

* Allowing the configuration of {kib} in a FIPS 140-2 compliant manner, as documented below.

==== Configuring {kib} for FIPS 140-2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to do anything about

## enable OpenSSL 3 legacy provider
--openssl-legacy-provider

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question 😅 Im not sure how that conflicts in a FIPS setup. I can do some investigation.

Is there anyway the KB admin could override this currently?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be removed, Kibana archives will have this at $KIBANA_HOME/config/node.options. or for deb/rpm /etc/kibana/node.options.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's ok to leave. You can use multiple providers alongside the FIPS provider. In #183777 I ran the FIPS agent pipeline appending FIPS options to the existing node.options without issue. That said, not sure it's "FIPS compliant" and still worth double checking @kc13greiner.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, we should be able to leave it:

When I configure node with:

[provider_sect]
default = default_sect
# The fips section name should match the section name inside the
# included fipsmodule.cnf.
# fips = fips_sect
legacy = legacy_sect

It runs with the legacy provider (w/o FIPS) and allows md4/md5

Screenshot 2024-06-11 at 5 25 10 PM

If I include fips as a provider, unsupported algorithms are not allowed and it doesn't even mention legacy mode anymore

[provider_sect]
default = default_sect
# The fips section name should match the section name inside the
# included fipsmodule.cnf.
fips = fips_sect
legacy = legacy_sect
Screenshot 2024-06-11 at 5 26 56 PM


Apart from setting `xpack.security.experimental.fipsMode.enabled` to `true` in your {kib} config, a number of security related
settings need to be reviewed and configured in order to run {kib} successfully in a FIPS 140-2 compliant Node.js
environment.

===== Kibana keystore

FIPS 140-2 (via NIST Special Publication 800-132) dictates that encryption keys should at least have an effective
strength of 112 bits. As such, the Kibana keystore that stores the application’s secure settings needs to be
password protected with a password that satisfies this requirement. This means that the password needs to be 14 bytes
long which is equivalent to a 14 character ASCII encoded password, or a 7 character UTF-8 encoded password.

For more information on how to set this password, refer to the <<change-password,keystore documentation>>.

===== TLS keystore and keys

Keystores can be used in a number of General TLS settings in order to conveniently store key and trust material.
PKCS#12 keystores cannot be used in a FIPS 140-2 compliant Node.js environment. Avoid using these types of keystores.
Your FIPS 140-2 provider may provide a compliant keystore implementation that can be used, or you can use PEM encoded
files. To use PEM encoded key material, you can use the relevant `\*.key` and `*.certificate` configuration options,
and for trust material you can use `*.certificate_authorities`.

As an example, avoid PKCS#12 specific settings such as:

* `server.ssl.keystore.path`
* `server.ssl.truststore.path`
* `elasticsearch.ssl.keystore.path`
* `elasticsearch.ssl.truststore.path`

===== Limitations

Configuring {kib} to run in FIPS mode is still considered to be experimental. Not all features are guaranteed to
function as expected.
1 change: 1 addition & 0 deletions docs/user/security/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ include::authorization/index.asciidoc[]
include::authorization/kibana-privileges.asciidoc[]
include::api-keys/index.asciidoc[]
include::role-mappings/index.asciidoc[]
include::fips-140-2.asciidoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ export function createPluginSetupContext<TPlugin, TPluginDependencies>({
},
security: {
registerSecurityDelegate: (api) => deps.security.registerSecurityDelegate(api),
fips: deps.security.fips,
},
userProfile: {
registerUserProfileDelegate: (delegate) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { SecurityServiceConfigType } from '../utils';
import { isFipsEnabled } from './fips';

describe('fips', () => {
describe('#isFipsEnabled', () => {
let config: SecurityServiceConfigType;

beforeAll(() => {
config = {};
});

afterEach(() => {
config = {};
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: I would ditch that part, given each test manually declare the config it need for its assertion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7b7ed01


it('should return `true` if config.experimental.fipsMode.enabled is `true`', () => {
config = { experimental: { fipsMode: { enabled: true } } };

expect(isFipsEnabled(config)).toBe(true);
});

it('should return `false` if config.experimental.fipsMode.enabled is `false`', () => {
config = { experimental: { fipsMode: { enabled: false } } };

expect(isFipsEnabled(config)).toBe(false);
});

it('should return `false` if config.experimental.fipsMode.enabled is `undefined`', () => {
expect(isFipsEnabled(config)).toBe(false);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { SecurityServiceConfigType } from '../utils';

export function isFipsEnabled(config: SecurityServiceConfigType): boolean {
return config?.experimental?.fipsMode?.enabled || false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: ?? false is technically more accurate

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7b7ed01

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ describe('SecurityService', () => {
);
});
});

describe('#fips', () => {
describe('#isEnabled', () => {
it('should return boolean', () => {
const { fips } = service.setup();

expect(fips.isEnabled()).toBe(false);
});
});
});
});

describe('#start', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,57 @@
import type { Logger } from '@kbn/logging';
import type { CoreContext, CoreService } from '@kbn/core-base-server-internal';
import type { CoreSecurityDelegateContract } from '@kbn/core-security-server';
import { Observable, Subscription } from 'rxjs';
import { Config } from '@kbn/config';
import { isFipsEnabled } from './fips/fips';
import type {
InternalSecurityServiceSetup,
InternalSecurityServiceStart,
} from './internal_contracts';
import { getDefaultSecurityImplementation, convertSecurityApi } from './utils';
import {
getDefaultSecurityImplementation,
convertSecurityApi,
SecurityServiceConfigType,
} from './utils';

export class SecurityService
implements CoreService<InternalSecurityServiceSetup, InternalSecurityServiceStart>
{
private readonly log: Logger;
private securityApi?: CoreSecurityDelegateContract;
private config$: Observable<Config>;
private configSubscription?: Subscription;
private config: Config | undefined;
private readonly getConfig = () => {
if (!this.config) {
throw new Error('Config is not available.');
}
return this.config;
};

constructor(coreContext: CoreContext) {
this.log = coreContext.logger.get('security-service');

this.config$ = coreContext.configService.getConfig$();
this.configSubscription = this.config$.subscribe((config) => {
this.config = config;
});
}

public setup(): InternalSecurityServiceSetup {
const config = this.getConfig();
const securityConfig: SecurityServiceConfigType = config.get(['xpack', 'security']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah... I overlooked we would need to access the security plugin's config from our core service for that feature 🙈.

With our security-in-core initiative, I think we'll want to move the security config from xpack.security.* to core.security.* at some point. It shouldn't be that much work (moving the schema registration + adding config deprecation + exposing the config type from core for the security plugin to be able to use them)

Without doing so, I agree that hacking around and accessing the raw config is the most pragmatic approach. It's absolutely against a dozen Core principles though, so would you mind opening a follow-up issue, just to keep track (and discuss) of moving the security config schema/registration to Core?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow up issue: #186863

Ill make a note to update this code once we move the config over


return {
registerSecurityDelegate: (api) => {
if (this.securityApi) {
throw new Error('security API can only be registered once');
}
this.securityApi = api;
},
fips: {
isEnabled: () => isFipsEnabled(securityConfig),
},
};
}

Expand All @@ -44,5 +71,10 @@ export class SecurityService
return convertSecurityApi(apiContract);
}

public stop() {}
public stop() {
if (this.configSubscription) {
this.configSubscription.unsubscribe();
this.configSubscription = undefined;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@

export { convertSecurityApi } from './convert_security_api';
export { getDefaultSecurityImplementation } from './default_implementation';

export interface SecurityServiceConfigType {
experimental?: {
fipsMode?: {
enabled: boolean;
};
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
"@kbn/core-http-server",
"@kbn/logging-mocks",
"@kbn/core-base-server-mocks",
"@kbn/config",
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { auditServiceMock, type MockedAuditService } from './audit.mock';
const createSetupMock = () => {
const mock: jest.Mocked<SecurityServiceSetup> = {
registerSecurityDelegate: jest.fn(),
fips: { isEnabled: jest.fn() },
};

return mock;
Expand All @@ -43,6 +44,7 @@ const createStartMock = (): SecurityStartMock => {
const createInternalSetupMock = () => {
const mock: jest.Mocked<InternalSecurityServiceSetup> = {
registerSecurityDelegate: jest.fn(),
fips: { isEnabled: jest.fn() },
};

return mock;
Expand Down
1 change: 1 addition & 0 deletions packages/core/security/core-security-server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ export type {
AuditRequest,
} from './src/audit_logging/audit_events';
export type { AuditLogger } from './src/audit_logging/audit_logger';
export type { CoreFipsService } from './src/fips';
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Side Public License, v 1.
*/

import { CoreFipsService } from './fips';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: import type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7b7ed01

import type { CoreAuthenticationService } from './authc';
import type { CoreSecurityDelegateContract } from './api_provider';
import type { CoreAuditService } from './audit';
Expand All @@ -21,6 +22,11 @@ export interface SecurityServiceSetup {
* @remark this should **exclusively** be used by the security plugin.
*/
registerSecurityDelegate(api: CoreSecurityDelegateContract): void;

/**
* The {{@link CoreFipsService | FIPS service}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: I don't think doubling {{ }} even works for tsdoc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7b7ed01

*/
fips: CoreFipsService;
}

/**
Expand Down
19 changes: 19 additions & 0 deletions packages/core/security/core-security-server/src/fips.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

/**
* Core's FIPS service
*
* @public
*/
export interface CoreFipsService {
/**
* Check if Kibana is configured to run in FIPS mode
*/
isEnabled(): boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ kibana_vars=(
xpack.security.authc.selector.enabled
xpack.security.cookieName
xpack.security.encryptionKey
xpack.security.experimental.fipsMode.enabled
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Thinking out loud there, but are we sure we want that under that experimental prefix instead of just flagging it as experimental in the documentation?

experimental config prefixes means once the feature leaves its experimental state, the config property name changes too, meaning another config deprecation to move it, and overall more work and maintenance.

So yeah, wouldn't documenting the flag as experimental be enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm torn; I want to really make clear that this config option should not be used at the moment, but I do see what you mean more work/rework.

@legrego @azasypkin What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm quite torn as well. We really do not want this to be exposed/configured yet, and documenting it goes against that goal.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think I'm in the "experimental-in-config-entry-name" camp mostly due to these reasons:

  • We absolutely don't want anyone outside of Elastic to use or even know about it at this point, no usual "deprecation" flow is assumed. It's experimental in the broadest sense, it can theoretically lead to all sorts of consequences from unexpected downtime to data loss or violated security expectations.
  • If anyone happens to figure out that such a setting exists and tries to use it before we can commit to supporting FIPS, well, that's on them. But when we're ready to officially support FIPS, we want to make sure they cannot upgrade before they go and read about the scope of FIPS support, expectations, and proper configuration that might potentially include other settings they will need to configure in addition to fipsMode.enabled.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 fair enough, thanks for explaining the reasoning

xpack.security.loginAssistanceMessage
xpack.security.loginHelp
xpack.security.sameSiteCookies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { SecurityLicenseFeatures } from './license_features';

export interface SecurityLicense {
isLicenseAvailable(): boolean;
getLicenseType(): string | undefined;
getUnavailableReason: () => string | undefined;
isEnabled(): boolean;
getFeatures(): SecurityLicenseFeatures;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,10 @@ export interface SecurityLicenseFeatures {
* Describes the layout of the login form if it's displayed.
*/
readonly layout?: LoginLayout;

/**
* Indicates whether we allow FIPS mode
*/

readonly allowFips: boolean;
}
27 changes: 24 additions & 3 deletions x-pack/plugins/security/common/licensing/index.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,33 @@ import type { SecurityLicense, SecurityLicenseFeatures } from '@kbn/security-plu
export const licenseMock = {
create: (
features: Partial<SecurityLicenseFeatures> | Observable<Partial<SecurityLicenseFeatures>> = {},
licenseType: LicenseType = 'basic' // default to basic if this is not specified
licenseType: LicenseType = 'basic', // default to basic if this is not specified,
isAvailable: Observable<boolean> = of(true)
): jest.Mocked<SecurityLicense> => ({
isLicenseAvailable: jest.fn().mockReturnValue(true),
isLicenseAvailable: jest.fn().mockImplementation(() => {
let result = true;

isAvailable.subscribe((next) => {
result = next;
});

return result;
}),
getLicenseType: jest.fn().mockReturnValue(licenseType),
getUnavailableReason: jest.fn(),
isEnabled: jest.fn().mockReturnValue(true),
getFeatures: jest.fn().mockReturnValue(features),
getFeatures:
features instanceof Observable
? jest.fn().mockImplementation(() => {
let subbedFeatures: Partial<SecurityLicenseFeatures> = {};

features.subscribe((next) => {
subbedFeatures = next;
});

return subbedFeatures;
})
: jest.fn().mockReturnValue(features),
hasAtLeast: jest
.fn()
.mockImplementation(
Expand Down
Loading