Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
soctools-user-mgmt-ui
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Container registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
gn4-3-wp8-t3.1 SOC
soctools-user-mgmt-ui
Commits
c552f7f7
Commit
c552f7f7
authored
3 years ago
by
Václav Bartoš
Browse files
Options
Downloads
Patches
Plain Diff
load list of users from keycloak (configuration needed)
+ added requirements.txt
parent
38f34e83
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
main.py
+63
-20
63 additions, 20 deletions
main.py
requirements.txt
+6
-0
6 additions, 0 deletions
requirements.txt
templates/main.html
+8
-7
8 additions, 7 deletions
templates/main.html
with
77 additions
and
27 deletions
main.py
+
63
−
20
View file @
c552f7f7
# Example of minimal working WSGI script
from
flask
import
Flask
,
render_template
,
request
,
make_response
,
redirect
,
flash
from
flask_wtf
import
FlaskForm
from
wtforms
import
StringField
from
wtforms.validators
import
DataRequired
,
Email
import
requests
from
datetime
import
datetime
import
subprocess
app
=
Flask
(
__name__
)
app
.
secret_key
=
"
ASDF1234 - CHANGE ME!
"
# *** Configuration ***
# TODO get this from config/environment
CA_CERT
=
""
# path to secrets/CA/ca.crt
KEYCLOAK_BASE_URL
=
""
# https://{{soctoolsproxy}}:12443
KEYCLOAK_ADMIN_PASSWORD
=
""
# take from secrets/passwords/keykloak_admin (Note: should be keycloak, not keykloak)
# *** Custom Jinja filters ***
def
ts_to_str
(
ts
):
return
datetime
.
utcfromtimestamp
(
int
(
ts
)).
isoformat
(
sep
=
"
"
)
# TODO Do Keycloak really use UTC timestamps?
app
.
jinja_env
.
filters
[
"
ts_to_str
"
]
=
ts_to_str
# *** Functions to call other APIs ***
def
get_token
():
"""
Get admin
'
s OIDC token from Keycloak - needed to perform any administrative API call
"""
url
=
KEYCLOAK_BASE_URL
+
"
/auth/realms/master/protocol/openid-connect/token
"
data
=
{
"
client_id
"
:
"
admin-cli
"
,
"
username
"
:
"
admin
"
,
"
password
"
:
KEYCLOAK_ADMIN_PASSWORD
,
"
grant_type
"
:
"
password
"
}
try
:
resp
=
requests
.
post
(
url
,
data
,
verify
=
CA_CERT
)
if
resp
.
status_code
!=
200
:
flash
(
f
"
ERROR: Can
'
t get token for API access: (
{
resp
.
status_code
}
)
{
resp
.
text
[
:
200
]
}
"
,
"
error
"
)
return
None
return
str
(
resp
.
json
()[
'
access_token
'
])
except
Exception
as
e
:
flash
(
f
"
ERROR: Can
'
t get token for API access:
{
type
(
e
).
__name__
}
:
{
e
}
"
,
"
error
"
)
return
None
def
get_users
():
# Get list of users from Keycloak
url
=
KEYCLOAK_BASE_URL
+
"
/auth/admin/realms/SOCTOOLS1/users
"
token
=
get_token
()
if
token
is
None
:
return
[]
# can't get token, error message is already flashed by get_token function
resp
=
requests
.
get
(
url
,
headers
=
{
'
Authorization
'
:
'
Bearer
'
+
token
},
verify
=
CA_CERT
)
if
not
resp
.
ok
:
flash
(
f
"
ERROR: Can
'
t get list of users: (
{
resp
.
status_code
}
)
{
resp
.
text
[
:
200
]
}
"
,
"
error
"
)
return
[]
try
:
users
=
resp
.
json
()
assert
isinstance
(
users
,
list
)
and
all
(
isinstance
(
o
,
dict
)
for
o
in
users
),
""
except
(
ValueError
,
AssertionError
):
flash
(
f
"
ERROR: Can
'
t get list of users: Unexpected content of response from Keycloak
"
,
"
error
"
)
return
[]
return
users
# *** Flask endpoints and forms ***
class
AddUserForm
(
FlaskForm
):
username
=
StringField
(
"
Username
"
,
validators
=
[
DataRequired
()])
cn
=
StringField
(
"
Common name (CN)
"
,
validators
=
[
DataRequired
()])
firstname
=
StringField
(
"
First name
"
,
validators
=
[])
lastname
=
StringField
(
"
Last name
"
,
validators
=
[])
# TODO what about CN/DN - construct from first+last name or allow to redefine?
email
=
StringField
(
"
Email
"
,
validators
=
[
DataRequired
(),
Email
()])
# DN is constructed automatically from CN
@app.route
(
"
/
"
,
methods
=
[
"
GET
"
,
"
POST
"
])
def
main
():
# TODO Load existing users (from where?)
users
=
[{
"
firstname
"
:
"
User1
"
,
"
lastname
"
:
"
SOC
"
,
"
username
"
:
"
user1
"
,
"
email
"
:
"
user1@example.org
"
,
"
DN
"
:
"
CN=User1Soctools
"
,
"
CN
"
:
"
User1Soctools
"
,
},{
"
firstname
"
:
"
User2
"
,
"
lastname
"
:
"
SOC
"
,
"
username
"
:
"
user2
"
,
"
email
"
:
"
user2@example.org
"
,
"
DN
"
:
"
CN=User2Soctools
"
,
"
CN
"
:
"
User2Soctools
"
,
}]
# Add user
# Load existing users from Keycloak
users
=
get_users
()
#print(users)
# Add user form
form_add_user
=
AddUserForm
()
if
form_add_user
.
validate_on_submit
():
# TODO check that username doesn't exist, yet (and check validity, i.e. special characters etc.)
...
...
This diff is collapsed.
Click to expand it.
requirements.txt
0 → 100644
+
6
−
0
View file @
c552f7f7
flask
~=2.1.0
flask_wtf
~=1.0.0
wtforms
~=3.0.1
email-validator
~=1.1.3
requests
~=2.27.1
jinja2
~=3.1.1
\ No newline at end of file
This diff is collapsed.
Click to expand it.
templates/main.html
+
8
−
7
View file @
c552f7f7
...
...
@@ -20,21 +20,22 @@
<h1>
SOCtools - User management
</h1>
<table>
<tr><th>
Username
</th><th>
First name
</th><th>
Last name
</th><th>
CN
</th><th>
email
</th><th></th>
<tr><th>
Username
</th><th>
First name
</th><th>
Last name
</th><th>
email
</th><th>
CN
</th><th>
DN
</th><th>
Time created
</th><th></th>
{% for user in users %}
<tr>
<td>
{{ user.username }}
</td>
<td>
{{ user.firstname }}
</td>
<td>
{{ user.lastname }}
</td>
<td>
{{ user.CN }}
</td>
<td>
{{ user.firstName }}
</td>
<td>
{{ user.lastName }}
</td>
<td>
{{ user.email }}
</td>
<td>
... {#TODO actions#}
</td>
<td>
{{ user.attributes.CN[0] }}
</td>
<td>
{{ user.attributes.DN[0] }}
</td>
<td>
{{ (user.createdTimestamp/1000)|ts_to_str }}
</td>
<td>
...
</td>
</tr>
{% endfor %}
</table>
<p></p>
<h2>
Add new user
</h2>
<form
action=
"{{ url_for("
main
")
}}"
method=
"POST"
>
{% if form_add_user.errors %}
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment