Skip to content

Commit ccea6c6

Browse files
authored
Merge pull request #372 from erwindon/customeauth
add support for additional salt.auth types
2 parents 99a3b3a + f674f27 commit ccea6c6

4 files changed

Lines changed: 96 additions & 51 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ yarn.lock
99
package-lock.json
1010
saltgui/static/minions.txt
1111
saltgui/static/mkMinions.sh
12+
saltgui/static/salt-auth.txt

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ SaltGUI supports the following authentication methods supported by salt:
7070
- mysql
7171
- yubico
7272

73+
Since pam by itself is already very powerfull, that one is mentionned as standard.
74+
By default, it provides access to the Linux password file,
75+
When other authentication methods need to be used their names can be added to file `saltgui/static/salt-auth.txt`.
76+
There is one name per line in that file. Choose the authentication methods that are activated
77+
in the salt-master configuration wisely, as the integrity of the salt-master and all salt-minions depends on it.
78+
7379
See the [EAUTH documentation](https://docs.saltstack.com/en/latest/topics/eauth/index.html) and the [Salt auth source code](https://github.com/saltstack/salt/tree/master/salt/auth) for more information.
7480

7581
## Command Box

saltgui/static/scripts/Api.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ export class API {
6868
return this.apiRequest("GET", "/static/minions.txt");
6969
}
7070

71+
getStaticSaltAuthTxt () {
72+
return this.apiRequest("GET", "/static/salt-auth.txt");
73+
}
74+
7175
getLocalBeaconsList (pMinionId) {
7276
const params = {
7377
"client": "local",

saltgui/static/scripts/panels/Login.js

Lines changed: 85 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -37,58 +37,9 @@ export class LoginPanel extends Panel {
3737

3838
// see https://docs.saltstack.com/en/latest/ref/auth/all/index.html
3939
const select = document.createElement("select");
40-
41-
const option1 = document.createElement("option");
42-
option1.id = "eauth-default";
43-
option1.value = "default";
44-
option1.innerText = "Type";
45-
select.append(option1);
46-
47-
const option2 = document.createElement("optgroup");
48-
option2.label = "standard";
49-
select.append(option2);
50-
51-
const option2a = document.createElement("option");
52-
option2a.value = "pam";
53-
option2a.innerText = "pam";
54-
option2.append(option2a);
55-
56-
// move items to this optgroup only when at least
57-
// one user reports a succesful use
58-
// see https://github.com/saltstack/salt/tree/master/salt/auth
59-
// for information and configuration
60-
const option3 = document.createElement("optgroup");
61-
option3.label = "other";
62-
select.append(option3);
63-
64-
const option3a = document.createElement("option");
65-
option3a.value = "file";
66-
option3a.innerText = "file";
67-
option3.append(option3a);
68-
69-
const option3b = document.createElement("option");
70-
option3b.value = "ldap";
71-
option3b.innerText = "ldap";
72-
option3.append(option3b);
73-
74-
const option3c = document.createElement("option");
75-
option3c.value = "mysql";
76-
option3c.innerText = "mysql";
77-
option3.append(option3c);
78-
79-
const option3d = document.createElement("option");
80-
option3d.value = "yubico";
81-
option3d.innerText = "yubico";
82-
option3.append(option3d);
83-
84-
// auto and sharedsecret already tested but not suitable for general use
85-
// other values are: django, keystone, pki, rest
86-
// these can be added after testing to optgroup 'other'
87-
// add untested values to (new) optgroup 'experimental' on explicit user request
88-
// and only while the code is on a branch
89-
9040
form.append(select);
9141
this.eauthField = select;
42+
this._updateEauthField();
9243

9344
const submit = document.createElement("input");
9445
submit.id = "login-button";
@@ -117,6 +68,57 @@ export class LoginPanel extends Panel {
11768
this._registerEventListeners(form);
11869
}
11970

71+
_addEauthSection (sectionName, optionValues) {
72+
if (optionValues.length === 0) {
73+
// no optionValues --> no section
74+
return;
75+
}
76+
77+
const optgroup = document.createElement("optgroup");
78+
optgroup.label = sectionName;
79+
this.eauthField.append(optgroup);
80+
81+
for (const optionValue of optionValues) {
82+
const option = document.createElement("option");
83+
option.value = optionValue;
84+
option.innerText = optionValue;
85+
optgroup.append(option);
86+
}
87+
}
88+
89+
_updateEauthField () {
90+
// start fresh
91+
this.eauthField.innerHTML = "";
92+
93+
const option1 = document.createElement("option");
94+
option1.id = "eauth-default";
95+
option1.value = "default";
96+
option1.innerText = "Type";
97+
this.eauthField.append(option1);
98+
99+
this._addEauthSection("standard", ["pam"]);
100+
101+
// move items to this optgroup only when at least
102+
// one user reports a succesful use
103+
// see https://github.com/saltstack/salt/tree/master/salt/auth
104+
// for information and configuration
105+
this._addEauthSection("other", ["file", "ldap", "mysql", "yubico"]);
106+
107+
// auto and sharedsecret already tested but not suitable for general use
108+
// other values are: django, keystone, pki, rest
109+
// these can be added after testing to optgroup 'other'
110+
// add untested values to (new) optgroup 'experimental' on explicit user request
111+
// and only while the code is on a branch
112+
113+
// allow user to add any value they want
114+
const saltAuthText = Utils.getStorageItem("local", "salt-auth-txt", "[]");
115+
const saltAuth = JSON.parse(saltAuthText);
116+
this._addEauthSection("salt-auth.txt", saltAuth);
117+
118+
this.eauthField.value = Utils.getStorageItem("local", "eauth", "pam");
119+
120+
}
121+
120122
_registerEventListeners (pLoginForm) {
121123
pLoginForm.addEventListener("submit", (ev) => {
122124
this._onLogin(ev);
@@ -134,8 +136,40 @@ export class LoginPanel extends Panel {
134136
this.noticeWrapperDiv.appendChild(noticeDiv);
135137
}
136138

139+
_loadSaltAuthTxt () {
140+
const staticSaltAuthTxtPromise = this.api.getStaticSaltAuthTxt();
141+
142+
staticSaltAuthTxtPromise.then((pStaticSaltAuthTxt) => {
143+
if (pStaticSaltAuthTxt) {
144+
const lines = pStaticSaltAuthTxt.
145+
trim().
146+
split(/\r?\n/).
147+
filter((item) => !item.startsWith("#"));
148+
const saltAuth = [];
149+
for (const line of lines) {
150+
const fields = line.split(/[ \t]+/);
151+
if (fields.length === 1) {
152+
saltAuth.push(fields[0]);
153+
} else {
154+
console.warn("lines in 'salt-auth.txt' must have 1 word, not " + fields.length + " like in: " + line);
155+
}
156+
}
157+
Utils.setStorageItem("local", "salt-auth-txt", JSON.stringify(saltAuth));
158+
this._updateEauthField();
159+
} else {
160+
Utils.setStorageItem("local", "salt-auth-txt", "[]");
161+
this._updateEauthField();
162+
}
163+
return true;
164+
}, () => {
165+
Utils.setStorageItem("local", "salt-auth-txt", "[]");
166+
this._updateEauthField();
167+
return false;
168+
});
169+
}
170+
137171
onShow () {
138-
this.eauthField.value = Utils.getStorageItem("local", "eauth", "pam");
172+
this._loadSaltAuthTxt();
139173

140174
const reason = decodeURIComponent(Utils.getQueryParam("reason"));
141175
switch (reason) {

0 commit comments

Comments
 (0)