Skip to content
Snippets Groups Projects
Commit 08821102 authored by Václav Bartoš's avatar Václav Bartoš
Browse files

User's CN is always set equal to username

There's no reason to make them different and this way it simplifies things (for example EasyRSA names certificate files by CN, but we usually identify user by its username).
parent 97fb6138
No related branches found
No related tags found
No related merge requests found
...@@ -6,9 +6,9 @@ The CA is based on the Easy-RSA tool which is used to manage everything around t ...@@ -6,9 +6,9 @@ The CA is based on the Easy-RSA tool which is used to manage everything around t
(all its config and data is in "<SOCTOOLS_BASE>/secrets/CA/"). (all its config and data is in "<SOCTOOLS_BASE>/secrets/CA/").
When a new user is created, a private key and a certificate with his/her username as CN are generated by Easy-RSA When a new user is created, a private key and a certificate with his/her username as CN are generated by Easy-RSA
in the background (stored into ".../CA/issued/<username>.crt"). # TODO check in the background (stored into ".../CA/issued/<CN>.crt").
The user is emailed with an URL containing a unique token allowing him/her to export and download the certificate and The user is emailed with an URL containing a unique token allowing him/her to export and download the certificate and
private key in the .p12 format. # TODO other formats? private key in the PKCS12 (.p12) and PEM (.key, .crt) formats.
The linkage of these tokens to usernames is stored in a local file at: "<SOCTOOLS_BASE>/secrets/cert_access_tokens" The linkage of these tokens to usernames is stored in a local file at: "<SOCTOOLS_BASE>/secrets/cert_access_tokens"
Format: "token,username,expiration-time" per line Format: "token,username,expiration-time" per line
...@@ -72,7 +72,7 @@ class CertError(Exception): ...@@ -72,7 +72,7 @@ class CertError(Exception):
def generate_certificate(cn: str): def generate_certificate(cn: str):
"""Generate a new x509 certificate for given user. """Generate a new x509 certificate for given user.
The certificate and associated private key are stored as file in the Easy-RSA directory: The certificate and associated private key are stored as files in the Easy-RSA directory:
- cert (pem): <CA_DIR>/issued/<cn>.crt - cert (pem): <CA_DIR>/issued/<cn>.crt
- key (pem): <CA_DIR>/private/<cn>.key - key (pem): <CA_DIR>/private/<cn>.key
- both (p12): <CA_DIR>/private/<cn>.p12 - both (p12): <CA_DIR>/private/<cn>.p12
...@@ -174,7 +174,7 @@ def get_username_by_token(token: str) -> Optional[str]: ...@@ -174,7 +174,7 @@ def get_username_by_token(token: str) -> Optional[str]:
# ========================= # =========================
# Auxiliary functions # Auxiliary functions
def _check_cn(cn): def _check_cn(cn: str):
""" """
Check CN validity - it must be possible to store it as a filename, without changing directory Check CN validity - it must be possible to store it as a filename, without changing directory
......
...@@ -65,7 +65,7 @@ class UserAccount: ...@@ -65,7 +65,7 @@ class UserAccount:
email: str email: str
firstname: str firstname: str
lastname: str lastname: str
cn: str cn: str # preferably, CN should be the same as username (all users created via GUI satisfy it)
dn: str dn: str
kcid: Optional[str] = field(default=None) # keycloak ID kcid: Optional[str] = field(default=None) # keycloak ID
ts_created: Optional[datetime] = field(default=None) # timezone-aware datetime in UTC ts_created: Optional[datetime] = field(default=None) # timezone-aware datetime in UTC
...@@ -85,7 +85,7 @@ class UserAccount: ...@@ -85,7 +85,7 @@ class UserAccount:
"lastName": self.lastname, "lastName": self.lastname,
"email": self.email, "email": self.email,
"attributes": { "attributes": {
"CN": [self.cn], # TODO: should be equal to username "CN": [self.cn],
"DN": [f"CN={self.cn}"] "DN": [f"CN={self.cn}"]
}, },
} }
...@@ -241,11 +241,11 @@ def kc_delete_user(userid: str) -> None: ...@@ -241,11 +241,11 @@ def kc_delete_user(userid: str) -> None:
class AddUserForm(FlaskForm): class AddUserForm(FlaskForm):
username = StringField("Username", validators=[DataRequired()]) username = StringField("Username", validators=[DataRequired()])
cn = StringField("Common name (CN)", validators=[DataRequired()]) #cn = StringField("Common name (CN)", validators=[DataRequired()])
# "CN" is set to "username", DN is constructed automatically from CN
firstname = StringField("First name", validators=[]) firstname = StringField("First name", validators=[])
lastname = StringField("Last name", validators=[]) lastname = StringField("Last name", validators=[])
email = StringField("Email", validators=[DataRequired(), Email()]) email = StringField("Email", validators=[DataRequired(), Email()])
# DN is constructed automatically from CN
send_email = BooleanField("Automatically send email with an URL allowing the user to download his/her certificate.", send_email = BooleanField("Automatically send email with an URL allowing the user to download his/her certificate.",
default="checked", default="checked",
description="A certificate, signed by an internal SOCtools CA, is generated for each user. It allows " description="A certificate, signed by an internal SOCtools CA, is generated for each user. It allows "
...@@ -310,8 +310,9 @@ def add_user(): ...@@ -310,8 +310,9 @@ def add_user():
email=form_user.email.data, email=form_user.email.data,
firstname=form_user.firstname.data, firstname=form_user.firstname.data,
lastname=form_user.lastname.data, lastname=form_user.lastname.data,
cn=form_user.cn.data, # CN and DN are constructed from username
dn=f"CN={form_user.cn.data}") cn=form_user.username.data,
dn=f"CN={form_user.username.data}")
# Generate certificate # Generate certificate
try: try:
...@@ -366,7 +367,7 @@ def add_user(): ...@@ -366,7 +367,7 @@ def add_user():
def edit_user(username: str): def edit_user(username: str):
"""Edit existing user. On GET show user details, on POST update user params with new values.""" """Edit existing user. On GET show user details, on POST update user params with new values."""
try: try:
user = kc_get_user_by_name(username) # TODO catch exception user = kc_get_user_by_name(username)
except KeycloakError as e: except KeycloakError as e:
flash(f'ERROR: {e}', "error") flash(f'ERROR: {e}', "error")
return redirect('/') return redirect('/')
...@@ -377,12 +378,12 @@ def edit_user(username: str): ...@@ -377,12 +378,12 @@ def edit_user(username: str):
if form_user.validate_on_submit(): if form_user.validate_on_submit():
# Form submitted and valid - perform account update # Form submitted and valid - perform account update
new_user = UserAccount(username=form_user.username.data, new_user = UserAccount(username=form_user.username.data,
email=form_user.email.data, email=form_user.email.data,
firstname=form_user.firstname.data, firstname=form_user.firstname.data,
lastname=form_user.lastname.data, lastname=form_user.lastname.data,
cn=form_user.cn.data, cn=form_user.username.data,
dn=f"CN={form_user.cn.data}", dn=f"CN={form_user.username.data}",
kcid=keycloak_id) kcid=keycloak_id)
# Keycloak # Keycloak
try: try:
kc_update_user(new_user) kc_update_user(new_user)
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
{{ form_user.username.label }} {{ form_user.username(size=20, readonly=True if user else False) }}<br> {{ form_user.username.label }} {{ form_user.username(size=20, readonly=True if user else False) }}<br>
{{ form_user.firstname.label }} {{ form_user.firstname(size=20) }}<br> {{ form_user.firstname.label }} {{ form_user.firstname(size=20) }}<br>
{{ form_user.lastname.label }} {{ form_user.lastname(size=20) }}<br> {{ form_user.lastname.label }} {{ form_user.lastname(size=20) }}<br>
{{ form_user.cn.label }} {{ form_user.cn(size=20) }}<br>
{{ form_user.email.label }} {{ form_user.email(size=20) }}<br> {{ form_user.email.label }} {{ form_user.email(size=20) }}<br>
{% if user %} {% if user %}
<input type="submit" value="Update user"> <input type="submit" value="Update user">
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment