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

Elastic auth; Kratos upgrade; Change SOC timezone; PCAP lookups include time range #35

Merged
merged 11 commits into from
Jun 15, 2021
3 changes: 1 addition & 2 deletions Dockerfile.kratos
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ RUN git clone https://github.com/ory/kratos.git

WORKDIR /go/src/github.com/ory/kratos

RUN git checkout v0.5.5-alpha.1
RUN git checkout v0.6.3-alpha.1

ENV GO111MODULE on
ENV CGO_ENABLED 1

RUN go mod download
RUN make pack
RUN go build -tags sqlite -a

FROM ghcr.io/security-onion-solutions/alpine:latest
Expand Down
4 changes: 4 additions & 0 deletions config/serverconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type ServerConfig struct {
ModuleFailuresIgnored bool `json:"moduleFailuresIgnored"`
ClientParams ClientParameters `json:"client"`
IdleConnectionTimeoutMs int `json:"idleConnectionTimeoutMs"`
TimezoneScript string `json:"timezoneScript"`
}

func (config *ServerConfig) Verify() error {
Expand All @@ -51,5 +52,8 @@ func (config *ServerConfig) Verify() error {
if (config.IdleConnectionTimeoutMs <= 0) {
config.IdleConnectionTimeoutMs = DEFAULT_IDLE_CONNECTION_TIMEOUT_MS
}
if len(config.TimezoneScript) == 0 {
config.TimezoneScript = "/opt/sensoroni/scripts/timezones.sh"
}
return err
}
3 changes: 3 additions & 0 deletions config/serverconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ func TestVerifyServer(tester *testing.T) {
if err != nil {
tester.Errorf("expected no error")
}
if cfg.TimezoneScript != "/opt/sensoroni/scripts/timezones.sh" {
tester.Errorf("Unexpected default timezone script: %s", cfg.TimezoneScript)
}
}
44 changes: 30 additions & 14 deletions html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@
</v-btn>
</template>
<v-list id="top-menu">
<v-list-item>
<v-list-item-content>
<v-list-item-title v-text="username"></v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-divider></v-divider>
<v-list-item @click.stop="toggleTheme">
<v-list-item-action>
<v-icon class="mx-auto">fa-adjust</v-icon>
Expand Down Expand Up @@ -255,23 +261,31 @@ <h2 v-text="i18n.home"></h2>
<v-col cols="3">
<h2 v-text="i18n[category]"></h2>
</v-col>
<v-col cols="4">
<v-switch v-if="isAdvanced()" id="auto-hunt" :disabled="loading()" v-model="autohunt" dense hide-details class="my-0" :label="i18n.autohunt"></v-switch>
<v-switch v-for="toggle in filterToggles" :key="toggle.name"
:id="'filterToggle-' + toggle.name"
:disabled="loading()"
v-model="toggle['enabled']"
dense hide-details class="my-0"
@click="filterToggled($event, toggle)"
:label="$root.localizeMessage(toggle.name)" @click="notifyInputsChanged()"></v-switch>
</v-col>
<v-col cols="2">
<v-select id="autoRefresh" class="ml-" :disabled="loading()" v-model="autoRefreshInterval" :items="autoRefreshIntervals" :hint="i18n.autoRefresh" persistent-hint prepend-icon="fa-hourglass-half"></v-select>
<v-col cols="5">
<v-expansion-panels>
<v-expansion-panel>
<v-expansion-panel-header id="huntOptionsHeader">{{i18n.options}}</v-expansion-panel-header>
<v-expansion-panel-content>
<v-switch v-if="isAdvanced()" id="auto-hunt" :disabled="loading()" v-model="autohunt" dense hide-details class="my-0" :label="i18n.autohunt"></v-switch>
<v-switch v-for="toggle in filterToggles" :key="toggle.name"
:id="'filterToggle-' + toggle.name"
:disabled="loading()"
v-model="toggle['enabled']"
dense hide-details class="my-0"
@click="filterToggled($event, toggle)"
:label="$root.localizeMessage(toggle.name)" @click="notifyInputsChanged()"></v-switch>
<v-select id="autoRefresh" class="ml-" :disabled="loading()" v-model="autoRefreshInterval" :items="autoRefreshIntervals" :hint="i18n.autoRefresh" persistent-hint prepend-icon="fa-hourglass-half"></v-select>
<v-select :disabled="loading()" @change="saveTimezone" v-model="zone" :items="$root.timezones" :hint="i18n.timezoneHelp" persistent-hint prepend-icon="fa-user-clock"></v-select>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-col>
<v-col cols="3" align="end">
<v-spacer></v-spacer>
<v-col cols="2" align="end">
<h4 v-if="loaded">{{ i18n.eventTotal }} {{ totalEvents.toLocaleString() }}</h4>
<p>
<h5>{{ i18n.timezone }} {{ zone }}</h5>
<h5>
</h5>
</v-col>
</v-row>
<v-row align="start">
Expand Down Expand Up @@ -786,6 +800,7 @@ <h2 v-text="i18n.users"></h2>
<v-text-field v-model="form.firstName" :placeholder="i18n.firstName"></v-text-field>
<v-text-field v-model="form.lastName" :placeholder="i18n.lastName"></v-text-field>
<v-text-field name="csrf_token" v-model="form.csrfToken" class="d-none"></v-text-field>
<v-text-field name="method" v-model="form.method" class="d-none"></v-text-field>
</v-col>
</v-row>
</v-container>
Expand Down Expand Up @@ -1207,6 +1222,7 @@ <h3 class="mb-4" v-text="i18n.updateProfile"></h3>
<v-text-field name="password" v-model="form.password" :placeholder="i18n.passwordChange" :type="showPassword ? 'text' : 'password'" @click:append="showPassword = !showPassword" :append-icon="showPassword ? 'fa-eye-slash' : 'fa-eye'" :rules="[rules.required]"></v-text-field>
<v-text-field :placeholder="i18n.passwordConfirm" :type="showPassword ? 'text' : 'password'" @click:append="showPassword = !showPassword" :append-icon="showPassword ? 'fa-eye-slash' : 'fa-eye'" :rules="[rules.required, rules.matches]"></v-text-field>
<v-text-field name="csrf_token" v-model="form.csrfToken" class="d-none"></v-text-field>
<v-text-field name="method" v-model="form.method" class="d-none"></v-text-field>
<v-btn type="submit" color="primary" :disabled="!form.valid" v-text="i18n.save"></v-btn>
</v-col>
</v-row>
Expand Down
10 changes: 9 additions & 1 deletion html/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ $(document).ready(function() {
usersLoadedDate: null,
cacheRefreshIntervalMs: 300000,
loadServerSettingsTime: 0,
user: null,
username: '',
},
watch: {
'$vuetify.theme.dark': 'saveLocalSettings',
Expand Down Expand Up @@ -214,7 +216,7 @@ $(document).ready(function() {
},
getDynamicActionFieldNames(url) {
const fields = [];
const matches = url.matchAll(/\{:([a-zA-Z0-9_.]+?)(\|.*?)?\}/g);
const matches = url.matchAll(/\{:([@a-zA-Z0-9_.]+?)(\|.*?)?\}/g);
for (const match of matches) {
if (match.length > 1) {
fields.push(match[1]);
Expand Down Expand Up @@ -267,6 +269,12 @@ $(document).ready(function() {
this.parameters = response.data.parameters;
this.elasticVersion = response.data.elasticVersion;
this.wazuhVersion = response.data.wazuhVersion;
this.timezones = response.data.timezones;

this.user = await this.getUserById(response.data.userId);
if (this.user) {
this.username = this.user.email;
}

if (this.parameterCallback != null) {
this.parameterCallback(this.parameters[this.parameterSection]);
Expand Down
2 changes: 2 additions & 0 deletions html/js/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ const i18n = {
ok: 'OK',
offline: 'Offline',
online: 'Online',
options: 'Options',
owner: 'Owner',
packages: 'Packages',
packets: 'Captured Packets',
Expand Down Expand Up @@ -285,6 +286,7 @@ const i18n = {
timestamp: 'Timestamp',
timestampFormat: 'YYYY-MM-DD HH:mm:ss.SSS Z',
timezone: 'Time Zone:',
timezoneHelp: 'Time Zone',
toolCyberchef: 'CyberChef',
toolCyberchefHelp: 'Data decoding and transformation tools',
toolFleet: 'FleetDM',
Expand Down
7 changes: 7 additions & 0 deletions html/js/routes/hunt.js
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,9 @@ const huntComponent = {
localStorage.removeItem(item);
}
},
saveTimezone() {
localStorage['timezone'] = this.zone;
},
saveLocalSettings() {
this.saveSetting('groupBySortBy', this.groupBySortBy, 'timestamp');
this.saveSetting('groupBySortDesc', this.groupBySortDesc, true);
Expand All @@ -1073,6 +1076,10 @@ const huntComponent = {
this.saveSetting('autohunt', this.autohunt, true);
},
loadLocalSettings() {
// Global settings
if (localStorage['timezone']) this.zone = localStorage['timezone'];

// Module settings
var prefix = 'settings.' + this.category;
if (localStorage[prefix + '.groupBySortBy']) this.groupBySortBy = localStorage[prefix + '.groupBySortBy'];
if (localStorage[prefix + '.groupBySortDesc']) this.groupBySortDesc = localStorage[prefix + '.groupBySortDesc'] == "true";
Expand Down
8 changes: 8 additions & 0 deletions html/js/routes/hunt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,11 @@ test('sortAlertsAscending', () => {
expect(sorted[1]).toBe(item3);
expect(sorted[0]).toBe(item4);
});

test('saveTimezone', () => {
comp.zone = "Foo/Bar";
comp.saveTimezone();
comp.zone = "Test";
comp.loadLocalSettings();
expect(comp.zone).toBe("Foo/Bar");
});
13 changes: 9 additions & 4 deletions html/js/routes/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ routes.push({ path: '*', name: 'login', component: {
email: null,
password: null,
csrfToken: null,
method: null,
},
rules: {
required: value => !!value || this.$root.i18n.required,
Expand All @@ -30,7 +31,7 @@ routes.push({ path: '*', name: 'login', component: {
this.$root.showLogin();
} else {
this.showLoginForm = true;
this.authLoginUrl = this.$root.authUrl + 'login/methods/password' + location.search;
this.authLoginUrl = this.$root.authUrl + 'login' + location.search;
this.loadData()
}
},
Expand All @@ -44,9 +45,13 @@ routes.push({ path: '*', name: 'login', component: {
this.banner = marked(response.data);
}
response = await this.$root.authApi.get('login/flows?id=' + this.$root.getAuthFlowId());
this.form.csrfToken = response.data.methods.password.config.fields.find(item => item.name == 'csrf_token').value;
if (response.data.methods.password.config.messages) {
this.$root.showWarning(this.i18n.loginInvalid);
this.form.csrfToken = response.data.ui.nodes.find(item => item.attributes && item.attributes.name == 'csrf_token').attributes.value;
this.form.method = response.data.ui.nodes.find(item => item.attributes && item.attributes.name == 'method').attributes.value;
if (response.data.ui.messages) {
const error = response.data.ui.messages.find(item => item.type == "error");
if (error && error.text) {
this.$root.showWarning(this.i18n.loginInvalid);
}
}
} catch (error) {
if (error.response.status == 410) {
Expand Down
18 changes: 9 additions & 9 deletions html/js/routes/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ routes.push({ path: '/settings', name: 'settings', component: {
usingDefaults: false,
form: {
valid: false,
email: null,
password: null,
csrfToken: null,
method: null,
},
rules: {
required: value => !!value || this.$root.i18n.required,
Expand All @@ -31,7 +31,7 @@ routes.push({ path: '/settings', name: 'settings', component: {
this.reloadSettings();
} else {
this.showSettingsForm = true;
this.authSettingsUrl = this.$root.authUrl + 'settings/methods/password' + location.search;
this.authSettingsUrl = this.$root.authUrl + 'settings' + location.search;
this.loadData()
}
this.usingDefaults = localStorage.length == 0;
Expand All @@ -49,15 +49,15 @@ routes.push({ path: '/settings', name: 'settings', component: {
async loadData() {
try {
const response = await this.$root.authApi.get('settings/flows?id=' + this.$root.getAuthFlowId());
this.form.csrfToken = response.data.methods.password.config.fields.find(item => item.name == 'csrf_token').value;
this.form.csrfToken = response.data.ui.nodes.find(item => item.attributes && item.attributes.name == 'csrf_token').attributes.value;
this.form.method = "password";
var errors = [];
response.data.methods.password.config.fields.forEach(function(value, index, array) {
if (value.messages) {
value.messages.forEach(function(err, idx, errArray) {
errors.push(err.text);
});
if (response.data.ui.messages) {
const error = response.data.ui.messages.find(item => item.type == "error");
if (error && error.text) {
errors.push(error.text);
}
});
}
if (errors.length > 0) {
this.$root.showWarning(this.i18n.settingsInvalid + errors.join("\n"));
} else if (response.data.state == "success") {
Expand Down
1 change: 1 addition & 0 deletions html/js/test_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
global.document = {};
global.navigator = {};
global.location = {};
global.localStorage = {};
global.btoa = function(content) {
return Buffer.from(content, 'binary').toString('base64');
};
Expand Down
3 changes: 2 additions & 1 deletion html/login/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@
</v-row>
<v-row>
<v-col xs12>
<v-text-field name="identifier" v-model="form.email" :placeholder="i18n.email" :hint="i18n.emailHelp" autofocus="true" :rules="[rules.required]"></v-text-field>
<v-text-field name="password_identifier" v-model="form.email" :placeholder="i18n.email" :hint="i18n.emailHelp" autofocus="true" :rules="[rules.required]"></v-text-field>
<v-text-field name="password" v-model="form.password" :placeholder="i18n.password" :type="showPassword ? 'text' : 'password'" @click:append="showPassword = !showPassword" :append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'" :rules="[rules.required]"></v-text-field>
<v-text-field name="csrf_token" v-model="form.csrfToken" class="d-none"></v-text-field>
<v-text-field name="method" v-model="form.method" class="d-none"></v-text-field>
</v-col>
</v-row>
</v-container>
Expand Down
2 changes: 2 additions & 0 deletions model/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ type Info struct {
Parameters *config.ClientParameters `json:"parameters"`
ElasticVersion string `json:"elasticVersion"`
WazuhVersion string `json:"wazuhVersion"`
UserId string `json:"userId"`
Timezones []string `json:"timezones"`
}
4 changes: 4 additions & 0 deletions scripts/timezones.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh

cd /usr/share/zoneinfo
find -type f | cut -c 3- | sort | grep -v ".tab\|tzdata\|right\/\|SystemV\/\|posix\/\|localtime\|Factory\|seconds\|posixrules"
24 changes: 17 additions & 7 deletions server/infohandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ import (
type InfoHandler struct {
web.BaseHandler
server *Server
timezones []string
}

func NewInfoHandler(srv *Server) *InfoHandler {
handler := &InfoHandler {}
handler.Host = srv.Host
handler.server = srv
handler.Impl = handler
handler.timezones = srv.GetTimezones()
return handler
}

Expand All @@ -40,12 +42,20 @@ func (infoHandler *InfoHandler) HandleNow(ctx context.Context, writer http.Respo
}

func (infoHandler *InfoHandler) get(ctx context.Context, writer http.ResponseWriter, request *http.Request) (int, interface{}, error) {
info := &model.Info{
Version: infoHandler.Host.Version,
License: "GPL v2",
Parameters: &infoHandler.server.Config.ClientParams,
ElasticVersion: os.Getenv("ELASTIC_VERSION"),
WazuhVersion: os.Getenv("WAZUH_VERSION"),
var err error
var info *model.Info
if user, ok := request.Context().Value(web.ContextKeyRequestor).(*model.User); ok {
info = &model.Info{
Version: infoHandler.Host.Version,
License: "GPL v2",
Parameters: &infoHandler.server.Config.ClientParams,
ElasticVersion: os.Getenv("ELASTIC_VERSION"),
WazuhVersion: os.Getenv("WAZUH_VERSION"),
UserId: user.Id,
Timezones: infoHandler.timezones,
}
} else {
err = errors.New("Unable to determine logged in user from context")
}
return http.StatusOK, info, nil
return http.StatusOK, info, err
}
Loading