mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
Add automatic host expiration capability (#2117)
When configured, this feature will delete hosts that have not checked in after the specified number of days. Closes #1860.
This commit is contained in:
parent
6439828272
commit
59efb495ca
19 changed files with 236 additions and 31 deletions
|
|
@ -4,7 +4,8 @@ jobs:
|
|||
docker:
|
||||
- image: golang:1.12
|
||||
- image: redis:5.0
|
||||
- image: mysql:5.7
|
||||
- image: mysql:5.7.27
|
||||
command: --event-scheduler=ON
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: toor
|
||||
MYSQL_DATABASE: kolide
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ services:
|
|||
image: mysql:5.7
|
||||
volumes:
|
||||
- .:/tmp
|
||||
command: mysqld --datadir=/tmp/mysqldata --slow_query_log=1 --log_output=TABLE --log-queries-not-using-indexes
|
||||
command: mysqld --datadir=/tmp/mysqldata --slow_query_log=1 --log_output=TABLE --log-queries-not-using-indexes --event-scheduler=ON
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: toor
|
||||
MYSQL_DATABASE: kolide
|
||||
|
|
@ -15,7 +15,7 @@ services:
|
|||
|
||||
mysql_test:
|
||||
image: mysql:5.7
|
||||
command: mysqld --datadir=/tmpfs --slow_query_log=1 --log_output=TABLE --log-queries-not-using-indexes
|
||||
command: mysqld --datadir=/tmpfs --slow_query_log=1 --log_output=TABLE --log-queries-not-using-indexes --event-scheduler=ON
|
||||
tmpfs: /tmpfs
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: toor
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ Fleet uses MySQL extensively as it's main database. Many cloud providers (such a
|
|||
|
||||
Fleet requires at least MySQL version 5.7.
|
||||
|
||||
For host expiry configuration, the [event scheduler](https://dev.mysql.com/doc/refman/5.7/en/events-overview.html) must be enabled. This can be enabled via the command line, configuration file, or a user with the required privileges.
|
||||
|
||||
#### Redis
|
||||
|
||||
Fleet uses Redis to ingest and queue the results of distributed queries, cache data, etc. Many cloud providers (such as [AWS](https://aws.amazon.com/elasticache/) and [GCP](https://console.cloud.google.com/launcher/details/click-to-deploy-images/redis)) host reliable Redis services which you may consider for this purpose. A well supported Redis [Docker container](https://hub.docker.com/_/redis/) also exists if you would rather run Redis in a container. For more information on how to configure the `fleet` binary to use the correct Redis instance, see the [Configuring The Fleet Binary](./configuring-the-fleet-binary.md) document.
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ const authTypeOptions = [
|
|||
];
|
||||
const baseClass = 'app-config-form';
|
||||
const formFields = [
|
||||
'authentication_method', 'authentication_type', 'domain', 'enable_ssl_tls', 'enable_start_tls',
|
||||
'kolide_server_url', 'org_logo_url', 'org_name', 'osquery_enroll_secret', 'password',
|
||||
'port', 'sender_address', 'server', 'user_name', 'verify_ssl_certs', 'idp_name', 'entity_id',
|
||||
'issuer_uri', 'idp_image_url', 'metadata', 'metadata_url', 'enable_sso', 'enable_smtp',
|
||||
'authentication_method', 'authentication_type', 'domain', 'enable_ssl_tls', 'enable_start_tls', 'kolide_server_url',
|
||||
'org_logo_url', 'org_name', 'osquery_enroll_secret', 'password', 'port', 'sender_address',
|
||||
'server', 'user_name', 'verify_ssl_certs', 'idp_name', 'entity_id', 'issuer_uri', 'idp_image_url',
|
||||
'metadata', 'metadata_url', 'enable_sso', 'enable_smtp', 'host_expiry_enabled', 'host_expiry_window',
|
||||
];
|
||||
const Header = ({ showAdvancedOptions }) => {
|
||||
const CaratIcon = <Icon name={showAdvancedOptions ? 'downcarat' : 'upcarat'} />;
|
||||
|
|
@ -61,6 +61,8 @@ class AppConfigForm extends Component {
|
|||
idp_name: formFieldInterface.isRequired,
|
||||
enable_sso: formFieldInterface.isRequired,
|
||||
enable_smtp: formFieldInterface.isRequired,
|
||||
host_expiry_enabled: formFieldInterface.isRequired,
|
||||
host_expiry_window: formFieldInterface.isRequired,
|
||||
}).isRequired,
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
smtpConfigured: PropTypes.bool.isRequired,
|
||||
|
|
@ -107,6 +109,8 @@ class AppConfigForm extends Component {
|
|||
<InputField {...fields.domain} label="Domain" />
|
||||
<Slider {...fields.verify_ssl_certs} label="Verify SSL Certs?" />
|
||||
<Slider {...fields.enable_start_tls} label="Enable STARTTLS?" />
|
||||
<Slider {...fields.host_expiry_enabled} label="Host Expiry" />
|
||||
<InputField {...fields.host_expiry_window} disabled={!fields.host_expiry_enabled.value} label="Host Expiry Window" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -114,6 +118,8 @@ class AppConfigForm extends Component {
|
|||
<p><strong>Domain</strong> - If you need to specify a HELO domain, you can do it here <em className="hint hint--brand">(Default: <strong>Blank</strong>)</em></p>
|
||||
<p><strong>Verify SSL Certs</strong> - Turn this off (not recommended) if you use a self-signed certificate <em className="hint hint--brand">(Default: <strong>On</strong>)</em></p>
|
||||
<p><strong>Enable STARTTLS</strong> - Detects if STARTTLS is enabled in your SMTP server and starts to use it. <em className="hint hint--brand">(Default: <strong>On</strong>)</em></p>
|
||||
<p><strong>Host Expiry</strong> - When enabled, allows automatic cleanup of hosts that have not communicated with Fleet in some number of days. <em className="hint hint--brand">(Default: <strong>Off</strong>)</em></p>
|
||||
<p><strong>Host Expiry Window</strong> - If a host has not communicated with Fleet in the specified number of days, it will be removed.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -74,17 +74,33 @@ describe('AppConfigForm - form', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('does not render advanced options by default', () => {
|
||||
expect(form.find({ name: 'domain' }).length).toEqual(0);
|
||||
expect(form.find('Slider').length).toEqual(0);
|
||||
});
|
||||
|
||||
describe('Advanced options', () => {
|
||||
it('does not render advanced options by default', () => {
|
||||
expect(form.find({ name: 'domain' }).length).toEqual(0);
|
||||
expect(form.find('Slider').length).toEqual(0);
|
||||
before(() => {
|
||||
form.find('.app-config-form__show-options').simulate('click');
|
||||
});
|
||||
|
||||
it('renders advanced options when "Advanced Options" is clicked', () => {
|
||||
form.find('.app-config-form__show-options').simulate('click');
|
||||
|
||||
expect(form.find({ name: 'domain' }).hostNodes().length).toEqual(1);
|
||||
expect(form.find('Slider').length).toEqual(2);
|
||||
expect(form.find('Slider').length).toEqual(3);
|
||||
});
|
||||
|
||||
it('disables host expiry window by default', () => {
|
||||
const InputField = form.find({ name: 'host_expiry_window' });
|
||||
const inputElement = InputField.find('input');
|
||||
expect(inputElement.length).toEqual(1);
|
||||
expect(inputElement.hasClass('input-field--disabled')).toBe(true);
|
||||
});
|
||||
|
||||
it('enables host expiry window', () => {
|
||||
form.find({ name: 'host_expiry_enabled' }).find('button').simulate('click');
|
||||
const InputField = form.find({ name: 'host_expiry_window' });
|
||||
const inputElement = InputField.find('input');
|
||||
expect(inputElement.hasClass('input-field--disabled')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ export default (formData) => {
|
|||
metadata_url: metadataURL,
|
||||
entity_id: entityID,
|
||||
idp_name: idpName,
|
||||
host_expiry_enabled: hostExpiryEnabled,
|
||||
host_expiry_window: hostExpiryWindow = 0,
|
||||
} = formData;
|
||||
|
||||
if (enableSSO) {
|
||||
|
|
@ -63,6 +65,12 @@ export default (formData) => {
|
|||
}
|
||||
}
|
||||
|
||||
if (hostExpiryEnabled) {
|
||||
if (isNaN(hostExpiryWindow) || Number(hostExpiryWindow) <= 0) {
|
||||
errors.host_expiry_window = 'Host Expiry Window must be a positive number';
|
||||
}
|
||||
}
|
||||
|
||||
const valid = !size(errors);
|
||||
|
||||
return { valid, errors };
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ describe('AppConfigForm - validations', () => {
|
|||
port: '1025',
|
||||
user_name: 'gnardog',
|
||||
password: 'p@ssw0rd',
|
||||
host_expiry_enabled: true,
|
||||
host_expiry_window: '42',
|
||||
};
|
||||
|
||||
it('returns a valid object when the form data is valid', () => {
|
||||
|
|
@ -174,4 +176,30 @@ describe('AppConfigForm - validations', () => {
|
|||
expect(validate(formData)).toEqual({ valid: true, errors: {} });
|
||||
});
|
||||
});
|
||||
|
||||
describe('host expiry settings', () => {
|
||||
it('does not validate missing expiry window', () => {
|
||||
const formData = {
|
||||
...validFormData,
|
||||
};
|
||||
delete formData.host_expiry_window;
|
||||
expect(validate(formData)).toEqual({ valid: false, errors: { host_expiry_window: 'Host Expiry Window must be a positive number' } });
|
||||
});
|
||||
|
||||
it('does not validate NaN expiry window', () => {
|
||||
const formData = {
|
||||
...validFormData,
|
||||
host_expiry_window: 'abcd',
|
||||
};
|
||||
expect(validate(formData)).toEqual({ valid: false, errors: { host_expiry_window: 'Host Expiry Window must be a positive number' } });
|
||||
});
|
||||
|
||||
it('does not validate negative expiry window', () => {
|
||||
const formData = {
|
||||
...validFormData,
|
||||
host_expiry_window: '-21',
|
||||
};
|
||||
expect(validate(formData)).toEqual({ valid: false, errors: { host_expiry_window: 'Host Expiry Window must be a positive number' } });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ export default PropTypes.shape({
|
|||
domain: PropTypes.string,
|
||||
enable_ssl_tls: PropTypes.bool,
|
||||
enable_start_tls: PropTypes.bool,
|
||||
host_expiry_enabled: PropTypes.bool,
|
||||
host_expiry_window: PropTypes.number,
|
||||
kolide_server_url: PropTypes.string,
|
||||
org_logo_url: PropTypes.string,
|
||||
org_name: PropTypes.string,
|
||||
|
|
|
|||
|
|
@ -83,17 +83,24 @@ export const formatConfigDataForServer = (config) => {
|
|||
const ssoSettingsAttrs = pick(config, ['entity_id', 'issuer_uri', 'idp_image_url', 'metadata',
|
||||
'metadata_url', 'idp_name', 'enable_sso',
|
||||
]);
|
||||
const hostExpirySettingsAttrs = pick(config, ['host_expiry_enabled', 'host_expiry_window']);
|
||||
|
||||
const orgInfo = size(orgInfoAttrs) && { org_info: orgInfoAttrs };
|
||||
const serverSettings = size(serverSettingsAttrs) && { server_settings: serverSettingsAttrs };
|
||||
const smtpSettings = size(smtpSettingsAttrs) && { smtp_settings: smtpSettingsAttrs };
|
||||
const ssoSettings = size(ssoSettingsAttrs) && { sso_settings: ssoSettingsAttrs };
|
||||
const hostExpirySettings = size(hostExpirySettingsAttrs) && { host_expiry_settings: hostExpirySettingsAttrs };
|
||||
|
||||
if (hostExpirySettings) {
|
||||
hostExpirySettings.host_expiry_settings.host_expiry_window = Number(hostExpirySettings.host_expiry_settings.host_expiry_window);
|
||||
}
|
||||
|
||||
return {
|
||||
...orgInfo,
|
||||
...serverSettings,
|
||||
...smtpSettings,
|
||||
...ssoSettings,
|
||||
...hostExpirySettings,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ describe('Kolide API - helpers', () => {
|
|||
authentication_method: 'authmethod_plain',
|
||||
verify_ssl_certs: true,
|
||||
enable_start_tls: true,
|
||||
host_expiry_enabled: false,
|
||||
host_expiry_window: 0,
|
||||
};
|
||||
|
||||
it('splits config into categories for the server', () => {
|
||||
|
|
@ -54,6 +56,13 @@ describe('Kolide API - helpers', () => {
|
|||
).toEqual({
|
||||
smtp_settings: { domain: 'https://kolide.co' },
|
||||
});
|
||||
expect(
|
||||
formatConfigDataForServer({ host_expiry_window: '12' })
|
||||
).toEqual({
|
||||
host_expiry_settings: {
|
||||
host_expiry_window: 12,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export const frontendFormattedConfig = (config) => {
|
|||
server_settings: serverSettings,
|
||||
smtp_settings: smtpSettings,
|
||||
sso_settings: ssoSettings,
|
||||
|
||||
host_expiry_settings: hostExpirySettings,
|
||||
} = config;
|
||||
|
||||
return {
|
||||
|
|
@ -12,6 +12,7 @@ export const frontendFormattedConfig = (config) => {
|
|||
...serverSettings,
|
||||
...smtpSettings,
|
||||
...ssoSettings,
|
||||
...hostExpirySettings,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,14 @@ describe('redux app node - helpers', () => {
|
|||
org_info: orgInfo,
|
||||
server_settings: serverSettings,
|
||||
smtp_settings: smtpSettings,
|
||||
host_expiry_settings: hostExpirySettings,
|
||||
} = configStub;
|
||||
|
||||
expect(frontendFormattedConfig(configStub)).toEqual({
|
||||
...orgInfo,
|
||||
...serverSettings,
|
||||
...smtpSettings,
|
||||
...hostExpirySettings,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ export const configStub = {
|
|||
verify_ssl_certs: true,
|
||||
enable_start_tls: true,
|
||||
},
|
||||
host_expiry_settings: {
|
||||
host_expiry_enabled: false,
|
||||
host_expiry_window: 0,
|
||||
},
|
||||
};
|
||||
|
||||
export const flatConfigStub = {
|
||||
|
|
@ -46,6 +50,8 @@ export const flatConfigStub = {
|
|||
authentication_method: 'authmethod_plain',
|
||||
verify_ssl_certs: true,
|
||||
enable_start_tls: true,
|
||||
host_expiry_enabled: false,
|
||||
host_expiry_window: 0,
|
||||
};
|
||||
|
||||
export const hostStub = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kolide/fleet/server/kolide"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
@ -23,7 +25,46 @@ func (d *Datastore) AppConfig() (*kolide.AppConfig, error) {
|
|||
return info, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) isEventSchedulerEnabled() (bool, error) {
|
||||
rows, err := d.db.Query("SELECT @@event_scheduler")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !rows.Next() {
|
||||
return false, errors.New("Error detecting MySQL event scheduler status.")
|
||||
}
|
||||
var value string
|
||||
if err := rows.Scan(&value); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return value == "ON", nil
|
||||
}
|
||||
|
||||
func (d *Datastore) ManageHostExpiryEvent(hostExpiryEnabled bool, hostExpiryWindow int) error {
|
||||
if !hostExpiryEnabled {
|
||||
_, err := d.db.Exec("DROP EVENT IF EXISTS host_expiry")
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := d.db.Exec(fmt.Sprintf("CREATE EVENT IF NOT EXISTS host_expiry ON SCHEDULE EVERY 1 HOUR ON COMPLETION PRESERVE DO DELETE FROM hosts WHERE seen_time < DATE_SUB(NOW(), INTERVAL %d DAY)", hostExpiryWindow))
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Datastore) SaveAppConfig(info *kolide.AppConfig) error {
|
||||
eventSchedulerEnabled, err := d.isEventSchedulerEnabled()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !eventSchedulerEnabled && info.HostExpiryEnabled {
|
||||
return errors.New("MySQL Event Scheduler must be enabled to configure Host Expiry.")
|
||||
}
|
||||
|
||||
if err := d.ManageHostExpiryEvent(info.HostExpiryEnabled, info.HostExpiryWindow); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Note that we hard code the ID column to 1, insuring that, if no rows
|
||||
// exist, a row will be created with INSERT, if a row does exist the key
|
||||
// will be violate uniqueness constraint and an UPDATE will occur
|
||||
|
|
@ -54,9 +95,11 @@ func (d *Datastore) SaveAppConfig(info *kolide.AppConfig) error {
|
|||
idp_name,
|
||||
enable_sso,
|
||||
fim_interval,
|
||||
fim_file_accesses
|
||||
fim_file_accesses,
|
||||
host_expiry_enabled,
|
||||
host_expiry_window
|
||||
)
|
||||
VALUES( 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
|
||||
VALUES( 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
|
||||
ON DUPLICATE KEY UPDATE
|
||||
org_name = VALUES(org_name),
|
||||
org_logo_url = VALUES(org_logo_url),
|
||||
|
|
@ -82,10 +125,12 @@ func (d *Datastore) SaveAppConfig(info *kolide.AppConfig) error {
|
|||
idp_name = VALUES(idp_name),
|
||||
enable_sso = VALUES(enable_sso),
|
||||
fim_interval = VALUES(fim_interval),
|
||||
fim_file_accesses = VALUES(fim_file_accesses)
|
||||
fim_file_accesses = VALUES(fim_file_accesses),
|
||||
host_expiry_enabled = VALUES(host_expiry_enabled),
|
||||
host_expiry_window = VALUES(host_expiry_window)
|
||||
`
|
||||
|
||||
_, err := d.db.Exec(insertStatement,
|
||||
_, err = d.db.Exec(insertStatement,
|
||||
info.OrgName,
|
||||
info.OrgLogoURL,
|
||||
info.KolideServerURL,
|
||||
|
|
@ -111,6 +156,8 @@ func (d *Datastore) SaveAppConfig(info *kolide.AppConfig) error {
|
|||
info.EnableSSO,
|
||||
info.FIMInterval,
|
||||
info.FIMFileAccesses,
|
||||
info.HostExpiryEnabled,
|
||||
info.HostExpiryWindow,
|
||||
)
|
||||
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package tables
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
func init() {
|
||||
MigrationClient.AddMigration(Up20191010101639, Down20191010101639)
|
||||
}
|
||||
|
||||
func Up20191010101639(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(
|
||||
"ALTER TABLE `app_configs` " +
|
||||
"ADD COLUMN `host_expiry_enabled` TINYINT(1) NOT NULL DEFAULT FALSE, " +
|
||||
"ADD COLUMN `host_expiry_window` int DEFAULT 0;",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20191010101639(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(
|
||||
"ALTER TABLE `app_configs` " +
|
||||
"DROP COLUMN `host_expiry_enabled`, " +
|
||||
"DROP COLUMN `host_expiry_window`;",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
@ -135,6 +135,11 @@ type AppConfig struct {
|
|||
FIMInterval int `db:"fim_interval"`
|
||||
// FIMFileAccess defines the FIMSections which will be monitored for file access events as a JSON formatted array
|
||||
FIMFileAccesses string `db:"fim_file_accesses"`
|
||||
|
||||
// HostExpiryEnabled defines whether automatic host cleanup is enabled.
|
||||
HostExpiryEnabled bool `db:"host_expiry_enabled"`
|
||||
// HostExpiryWindow defines a number in days after which a host will be removed if it has not communicated with Fleet.
|
||||
HostExpiryWindow int `db:"host_expiry_window"`
|
||||
}
|
||||
|
||||
// ModifyAppConfigRequest contains application configuration information
|
||||
|
|
@ -205,9 +210,10 @@ type SMTPSettingsPayload struct {
|
|||
// AppConfigPayload contains request/response format of
|
||||
// the AppConfig endpoints.
|
||||
type AppConfigPayload struct {
|
||||
OrgInfo *OrgInfo `json:"org_info"`
|
||||
ServerSettings *ServerSettings `json:"server_settings"`
|
||||
SMTPSettings *SMTPSettingsPayload `json:"smtp_settings"`
|
||||
OrgInfo *OrgInfo `json:"org_info"`
|
||||
ServerSettings *ServerSettings `json:"server_settings"`
|
||||
SMTPSettings *SMTPSettingsPayload `json:"smtp_settings"`
|
||||
HostExpirySettings *HostExpirySettings `json:"host_expiry_settings"`
|
||||
// SMTPTest is a flag that if set will cause the server to test email configuration
|
||||
SMTPTest *bool `json:"smtp_test,omitempty"`
|
||||
// SSOSettings single sign settings
|
||||
|
|
@ -226,6 +232,12 @@ type ServerSettings struct {
|
|||
EnrollSecret *string `json:"osquery_enroll_secret,omitempty"`
|
||||
}
|
||||
|
||||
// HostExpirySettings contains settings pertaining to automatic host expiry.
|
||||
type HostExpirySettings struct {
|
||||
HostExpiryEnabled *bool `json:"host_expiry_enabled,omitempty"`
|
||||
HostExpiryWindow *int `json:"host_expiry_window,omitempty"`
|
||||
}
|
||||
|
||||
type OrderDirection int
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ type appConfigRequest struct {
|
|||
}
|
||||
|
||||
type appConfigResponse struct {
|
||||
OrgInfo *kolide.OrgInfo `json:"org_info,omitemtpy"`
|
||||
ServerSettings *kolide.ServerSettings `json:"server_settings,omitempty"`
|
||||
SMTPSettings *kolide.SMTPSettingsPayload `json:"smtp_settings,omitempty"`
|
||||
SSOSettings *kolide.SSOSettingsPayload `json:"sso_settings,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
OrgInfo *kolide.OrgInfo `json:"org_info,omitemtpy"`
|
||||
ServerSettings *kolide.ServerSettings `json:"server_settings,omitempty"`
|
||||
SMTPSettings *kolide.SMTPSettingsPayload `json:"smtp_settings,omitempty"`
|
||||
SSOSettings *kolide.SSOSettingsPayload `json:"sso_settings,omitempty"`
|
||||
HostExpirySettings *kolide.HostExpirySettings `json:"host_expiry_settings,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r appConfigResponse) error() error { return r.Err }
|
||||
|
|
@ -35,7 +36,8 @@ func makeGetAppConfigEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
}
|
||||
var smtpSettings *kolide.SMTPSettingsPayload
|
||||
var ssoSettings *kolide.SSOSettingsPayload
|
||||
// only admin can see smtp settings
|
||||
var hostExpirySettings *kolide.HostExpirySettings
|
||||
// only admin can see smtp, sso, and host expiry settings
|
||||
if vc.CanPerformAdminActions() {
|
||||
smtpSettings = smtpSettingsFromAppConfig(config)
|
||||
if smtpSettings.SMTPPassword != nil {
|
||||
|
|
@ -50,6 +52,10 @@ func makeGetAppConfigEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
IDPName: &config.IDPName,
|
||||
EnableSSO: &config.EnableSSO,
|
||||
}
|
||||
hostExpirySettings = &kolide.HostExpirySettings{
|
||||
HostExpiryEnabled: &config.HostExpiryEnabled,
|
||||
HostExpiryWindow: &config.HostExpiryWindow,
|
||||
}
|
||||
}
|
||||
response := appConfigResponse{
|
||||
OrgInfo: &kolide.OrgInfo{
|
||||
|
|
@ -60,8 +66,9 @@ func makeGetAppConfigEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
KolideServerURL: &config.KolideServerURL,
|
||||
EnrollSecret: &config.EnrollSecret,
|
||||
},
|
||||
SMTPSettings: smtpSettings,
|
||||
SSOSettings: ssoSettings,
|
||||
SMTPSettings: smtpSettings,
|
||||
SSOSettings: ssoSettings,
|
||||
HostExpirySettings: hostExpirySettings,
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
@ -93,6 +100,10 @@ func makeModifyAppConfigEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
IDPName: &config.IDPName,
|
||||
EnableSSO: &config.EnableSSO,
|
||||
},
|
||||
HostExpirySettings: &kolide.HostExpirySettings{
|
||||
HostExpiryEnabled: &config.HostExpiryEnabled,
|
||||
HostExpiryWindow: &config.HostExpiryWindow,
|
||||
},
|
||||
}
|
||||
if response.SMTPSettings.SMTPPassword != nil {
|
||||
*response.SMTPSettings.SMTPPassword = "********"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ func testGetAppConfig(t *testing.T, r *testResource) {
|
|||
require.NotNil(t, *configInfo.OrgInfo)
|
||||
assert.Equal(t, "Kolide", *configInfo.OrgInfo.OrgName)
|
||||
assert.Equal(t, "http://foo.bar/image.png", *configInfo.OrgInfo.OrgLogoURL)
|
||||
assert.False(t, *configInfo.HostExpirySettings.HostExpiryEnabled)
|
||||
assert.Equal(t, 0, *configInfo.HostExpirySettings.HostExpiryWindow)
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +60,8 @@ func testModifyAppConfig(t *testing.T, r *testResource) {
|
|||
Metadata: "metadataxxxxxx",
|
||||
IssuerURI: "http://issuer.idp.com",
|
||||
EntityID: "kolide",
|
||||
HostExpiryEnabled: true,
|
||||
HostExpiryWindow: 42,
|
||||
}
|
||||
payload := appConfigPayloadFromAppConfig(config)
|
||||
payload.SMTPTest = new(bool)
|
||||
|
|
@ -80,14 +84,17 @@ func testModifyAppConfig(t *testing.T, r *testResource) {
|
|||
assert.Equal(t, config.OrgName, *respBody.OrgInfo.OrgName)
|
||||
saved, err := r.ds.AppConfig()
|
||||
require.Nil(t, err)
|
||||
// verify email test succeeded
|
||||
// verify email configuration succeeded
|
||||
assert.True(t, saved.SMTPConfigured)
|
||||
// verify that SSO stuff was saved
|
||||
// verify that SSO settings were saved
|
||||
assert.True(t, saved.EnableSSO)
|
||||
assert.Equal(t, "idpname", saved.IDPName)
|
||||
assert.Equal(t, "metadataxxxxxx", saved.Metadata)
|
||||
assert.Equal(t, "http://issuer.idp.com", saved.IssuerURI)
|
||||
assert.Equal(t, "kolide", saved.EntityID)
|
||||
// verify that host expiry settings were saved
|
||||
assert.True(t, saved.HostExpiryEnabled)
|
||||
assert.Equal(t, 42, saved.HostExpiryWindow)
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -135,5 +142,9 @@ func appConfigPayloadFromAppConfig(config *kolide.AppConfig) *kolide.AppConfigPa
|
|||
IssuerURI: &config.IssuerURI,
|
||||
EntityID: &config.EntityID,
|
||||
},
|
||||
HostExpirySettings: &kolide.HostExpirySettings{
|
||||
HostExpiryEnabled: &config.HostExpiryEnabled,
|
||||
HostExpiryWindow: &config.HostExpiryWindow,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,15 @@ func appConfigFromAppConfigPayload(p kolide.AppConfigPayload, config kolide.AppC
|
|||
}
|
||||
}
|
||||
|
||||
if p.HostExpirySettings != nil {
|
||||
if p.HostExpirySettings.HostExpiryEnabled != nil {
|
||||
config.HostExpiryEnabled = *p.HostExpirySettings.HostExpiryEnabled
|
||||
}
|
||||
if p.HostExpirySettings.HostExpiryWindow != nil {
|
||||
config.HostExpiryWindow = *p.HostExpirySettings.HostExpiryWindow
|
||||
}
|
||||
}
|
||||
|
||||
populateSMTP := func(p *kolide.SMTPSettingsPayload) {
|
||||
if p.SMTPAuthenticationMethod != nil {
|
||||
switch *p.SMTPAuthenticationMethod {
|
||||
|
|
|
|||
Loading…
Reference in a new issue