Skip to content

Commit

Permalink
feat(acls): introduce new ACL rewrite (#1472)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexisSouquiere authored Jun 26, 2023
1 parent 1172470 commit 4359e54
Show file tree
Hide file tree
Showing 104 changed files with 1,637 additions and 1,342 deletions.
103 changes: 57 additions & 46 deletions application.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,75 +186,86 @@ akhq:

# Auth & Roles (optional)
security:
roles:
topic-read:
- resources: [ "TOPIC", "TOPIC_DATA" ]
actions: [ "READ" ]
- resources: [ "TOPIC" ]
actions: [ "READ_CONFIG" ]
topic-admin:
- resources: [ "TOPIC", "TOPIC_DATA" ]
actions: [ "READ", "CREATE", "DELETE" ]
- resources: [ "TOPIC" ]
actions: [ "UPDATE", "READ_CONFIG", "ALTER_CONFIG" ]
connect-rw:
- resources: [ "CONNECTOR" ]
actions: [ "READ", "CREATE", "UPDATE_STATE" ]
connect-admin:
- resources: [ "CONNECTOR" ]
actions: [ "READ", "CREATE", "UPDATE_STATE", "DELETE" ]
registry-read:
- resources: [ "SCHEMA" ]
actions: [ "READ" ]
registry-admin:
- resources: [ "SCHEMA" ]
actions: [ "READ", "CREATE", "UPDATE", "DELETE", "DELETE_VERSION" ]
group-read:
- resources: [ "CONSUMER_GROUP" ]
actions: [ "READ" ]
connect-cluster-read:
- resources: [ "CONNECT_CLUSTER" ]
actions: [ "READ" ]
ksqldb-admin:
- resources: [ "KSQLDB" ]
actions: [ "READ", "EXECUTE" ]

default-group: admin # Default groups for all the user even unlogged user
# Groups definition
groups:
admin: # unique key
name: admin # Group name
roles: # roles for the group
- topic/read
- topic/insert
- topic/delete
- topic/config/update
- node/read
- node/config/update
- topic/data/read
- topic/data/insert
- topic/data/delete
- group/read
- group/delete
- group/offsets/update
- registry/read
- registry/insert
- registry/update
- registry/delete
- registry/version/delete
- acls/read
- connect/read
- connect/insert
- connect/update
- connect/delete
- connect/state/update
attributes:
# Regexp list to filter topic available for group
topics-filter-regexp:
- "test.*"
# Regexp list to filter connect configs visible for group
connects-filter-regexp:
- "^test.*$"
# Regexp list to filter consumer groups visible for group
consumer-groups-filter-regexp:
- "consumer.*"
topic-reader: # unique key
name: topic-reader # Other group
roles:
- topic/read
attributes:
topics-filter-regexp:
- "test\\.reader.*"
admin:
- role: topic-admin
- role: connect-admin
- role: registry-admin
- role: group-read
- role: connect-cluster-read
- role: ksqldb-admin
topic-reader:
- role: topic-read
- role: registry-admin
topic-reader-dev:
- role: topic-read
clusters: ["dev"]
- role: registry-admin
clusters: ["dev"]
topic-reader-project-prod:
- role: topic-read
patterns: ["project.*"]
clusters: ["prod.*"]
- role: registry-admin
patterns: ["project.*"]
clusters: ["prod.*"]

# Basic auth configuration
basic-auth:
- username: user # Username
password: pass # Password in sha256
groups: # Groups for the user
- admin
- topic-reader

# Ldap Groups configuration (when using ldap)
ldap:
default-group: topic-reader
groups:
- name: group-ldap-1
groups: # Akhq groups list
- topic-reader
- topic-reader-dev
- name: group-ldap-2
groups:
- admin
users:
- username: riemann # ldap user id
groups: # Akhq groups list
- topic-reader
- topic-reader-project-prod
- username: einstein
groups:
- admin
Expand Down
5 changes: 5 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"bootstrap": "^4.6.1",
"convert-units": "^2.3.4",
"css-loader": "^3.4.1",
"event-source-polyfill": "^1.0.31",
"font-awesome": "^4.7.0",
"joi-validation": "^2.0.0",
"lodash": "^4.17.21",
Expand Down
20 changes: 16 additions & 4 deletions client/src/components/Root/Root.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,28 @@ class Root extends Component {
}

getApi(url) {
return get(url, { cancelToken: this.cancel.token });
return get(url, this.buildConfig());
}
postApi(url, body) {
return post(url, body, { cancelToken: this.cancel.token });
return post(url, body, this.buildConfig());
}
putApi(url, body) {
return put(url, body, { cancelToken: this.cancel.token });
return put(url, body, this.buildConfig());
}
removeApi(url, body) {
return remove(url, body, { cancelToken: this.cancel.token });
return remove(url, body, this.buildConfig());
}

buildConfig() {
let config = new Map();
config.cancelToken = this.cancel.token;

if (sessionStorage.getItem('jwtToken')) {
config.headers = {};
config.headers['Authorization'] = 'Bearer ' + sessionStorage.getItem('jwtToken');
}

return config;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class ConnectConfigs extends Form {
disabled={
plugin.name === 'name' ||
plugin.name === 'connector.class' ||
!(roles.connect && roles.connect['connect/update'])
!(roles.CONNECT && roles.CONNECT.includes('UPDATE'))
}
placeholder={plugin.defaultValue > 0 ? plugin.defaultValue : ''}
onChange={({ currentTarget: input }) => {
Expand Down Expand Up @@ -332,7 +332,7 @@ class ConnectConfigs extends Form {
<tbody>{display}</tbody>
</table>
</div>
{roles.connect && roles.connect['connect/update'] && (
{roles.CONNECT && roles.CONNECT.include('UPDATE') && (
<div style={{ left: 0, width: '100%' }} className="khq-submit">
<button
type={'submit'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,14 +246,14 @@ class ConnectTasks extends Root {
this.setState({ tableData: data });
}}
actions={
roles.connect && roles.connect['connect/state/update'] && [constants.TABLE_RESTART]
roles.CONNECT && roles.CONNECT.includes('UPDATE_STATE') && [constants.TABLE_RESTART]
}
onRestart={row => {
this.handleAction(this.definitionState.RESTART_TASK, row.id);
}}
/>
</div>
{roles.connect && roles.connect['connect/state/update'] && (
{roles.CONNECT && roles.CONNECT.includes('UPDATE_STATE') && (
<aside>
{definition.paused ? (
<li className="aside-button">
Expand Down
6 changes: 3 additions & 3 deletions client/src/containers/Connect/ConnectList/ConnectList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,10 @@ class ConnectList extends Root {
const roles = this.state.roles || {};
let actions = [];

if (roles.connect && roles.connect['connect/read']) {
if (roles.CONNECT && roles.CONNECT.includes('READ')) {
actions.push(constants.TABLE_DETAILS);
}
if (roles.connect && roles.connect['connect/delete']) {
if (roles.CONNECT && roles.CONNECT.includes('DELETE')) {
actions.push(constants.TABLE_DELETE);
}

Expand Down Expand Up @@ -356,7 +356,7 @@ class ConnectList extends Root {
}}
noContent={'No connectors available'}
/>
{roles.connect && roles.connect['connect/insert'] && (
{roles.CONNECT && roles.CONNECT.includes('CREATE') && (
<aside>
<Link to={`/ui/${clusterId}/connect/${connectId}/create`} className="btn btn-primary">
Create a definition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class ConsumerGroup extends Component {
Members
</Link>
</li>
{roles.acls && roles.acls['acls/read'] && (
{roles.ACL && roles.ACL.includes('READ') && (
<li className="nav-item">
<Link
to={`/ui/${clusterId}/group/${consumerGroupId}/acls`}
Expand All @@ -132,19 +132,20 @@ class ConsumerGroup extends Component {
</div>
</div>

{roles.group &&
(roles.group['group/offsets/delete'] || roles.group['group/offsets/update']) && (
{roles.CONSUMER_GROUP &&
(roles.CONSUMER_GROUP.includes('DELETE_OFFSET') ||
roles.CONSUMER_GROUP.includes('UPDATE_OFFSET')) && (
<aside>
<li className="aside-button">
{roles.group['group/offsets/delete'] && (
{roles.CONSUMER_GROUP.includes('DELETE_OFFSET') && (
<Link
to={`/ui/${clusterId}/group/${consumerGroupId}/offsetsdelete`}
className="btn btn-secondary mr-2"
>
Delete Offsets
</Link>
)}
{roles.group['group/offsets/update'] && (
{roles.CONSUMER_GROUP.includes('UPDATE_OFFSET') && (
<Link
to={`/ui/${clusterId}/group/${consumerGroupId}/offsets`}
className="btn btn-primary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ class ConsumerGroupList extends Root {
}}
onDetails={id => `/ui/${selectedCluster}/group/${encodeURIComponent(id)}`}
actions={
roles.group && roles.group['group/delete']
roles.CONSUMER_GROUP && roles.CONSUMER_GROUP.includes('DELETE')
? [constants.TABLE_DELETE, constants.TABLE_DETAILS]
: [constants.TABLE_DETAILS]
}
Expand Down
1 change: 1 addition & 0 deletions client/src/containers/Header/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Header extends Root {
sessionStorage.setItem('login', currentUserData.logged);
sessionStorage.setItem('user', 'default');
sessionStorage.setItem('roles', organizeRoles(currentUserData.roles));
sessionStorage.removeItem('jwtToken');
this.setState({ login: currentUserData.logged }, () => {
this.props.history.replace({
pathname: '/ui/login',
Expand Down
2 changes: 1 addition & 1 deletion client/src/containers/KsqlDB/KsqlDBList/KsqlDBList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class KsqlDBList extends Component {
</div>
</div>
</div>
{roles && roles.ksqldb && roles.ksqldb['ksqldb/execute'] && (
{roles && roles.KSQDLDB && roles.KSQLDB.includes('EXECUTE') && (
<aside>
<li className="aside-button">
<Link
Expand Down
14 changes: 12 additions & 2 deletions client/src/containers/Login/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,18 @@ class Login extends Form {
password: formData.password
};

login(uriLogin(), body).then(() => {
this.getData();
login(uriLogin(), body).then(res => {
if (res.body) {
res.json().then(r => {
// Support JWT authentication through access_token
if (r.access_token) {
sessionStorage.setItem('jwtToken', r.access_token);
this.getData();
}
});
} else {
this.getData();
}
});
} catch (err) {
toast.error('Wrong Username or Password!');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ class NodeConfigs extends Form {
this.setState({ data });
}}
/>
{roles.node['node/config/update'] &&
{roles.NODE.includes('ALTER_CONFIG') &&
this.renderButton('Update configs', this.handleSubmit, undefined, 'submit')}
</div>
</form>
Expand Down
4 changes: 2 additions & 2 deletions client/src/containers/Schema/SchemaDetail/Schema.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Schema extends Root {
const { clusterId, schemaId, roles } = this.state;
let tabSelected = getSelectedTab(this.props, this.tabs);

if (!roles.registry['registry/update'] && tabSelected === 'update') {
if (!roles.SCHEMA.includes('UPDATE') && tabSelected === 'update') {
tabSelected = 'versions';
}

Expand Down Expand Up @@ -108,7 +108,7 @@ class Schema extends Root {
<Header title={`Schema: ${decodeURIComponent(schemaId)}`} history={this.props.history} />
<div className="tabs-container">
<ul className="nav nav-tabs" role="tablist">
{roles.registry['registry/update'] && (
{roles.SCHEMA.includes('UPDATE') && (
<li className="nav-item">
<Link
to={`/ui/${clusterId}/schema/details/${schemaId}/update`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class SchemaUpdate extends Form {
},
'col-sm-10'
)}
{roles.registry['registry/update'] &&
{roles.SCHEMA.includes('UPDATE') &&
this.renderButton('Update', undefined, undefined, 'submit')}
</fieldset>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ class SchemaVersions extends Root {
this.handleOnDelete(schema);
}}
actions={
roles.registry && roles.registry['registry/version/delete']
? [constants.TABLE_DELETE]
: []
roles.SCHEMA && roles.SCHEMA.includes('DELETE_VERSION') ? [constants.TABLE_DELETE] : []
}
extraRow
noStripes
Expand Down
4 changes: 2 additions & 2 deletions client/src/containers/Schema/SchemaList/SchemaList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ class SchemaList extends Root {
return `/ui/${selectedCluster}/schema/details/${encodeURIComponent(subject)}`;
}}
actions={
roles.registry && roles.registry['registry/delete']
roles.SCHEMA && roles.SCHEMA.includes('DELETE')
? [constants.TABLE_DELETE, constants.TABLE_DETAILS]
: [constants.TABLE_DETAILS]
}
Expand Down Expand Up @@ -297,7 +297,7 @@ class SchemaList extends Root {
}}
noContent={'No schemas available'}
/>
{roles.registry && roles.registry['registry/insert'] && (
{roles.SCHEMA && roles.SCHEMA.includes('CREATE') && (
<aside>
<Link
to={{
Expand Down
Loading

0 comments on commit 4359e54

Please sign in to comment.