Auth support (#25)

* initial auth implementation

* add create user parser

* add tests

* update dependencies list

* add login annd logout to index also improve auth

* realworld fixes

* add method set_option to Configuration and also use it everywhere
* split CreateUser handler to additional read method
* check user duplicate on auth mapping read
* generate salt by using passlib instead of random.choice
* case-insensetive usernames
* update dependencies
* update configuration reference
* improve tests

* fix codefactor errors

* hide fields if authorization is enabled, but no auth supplied

* add settings object for auth provider

* readme update
This commit is contained in:
2021-09-02 23:36:00 +03:00
committed by GitHub
parent 3922c55464
commit e63cb509f2
63 changed files with 2200 additions and 184 deletions

View File

@ -12,11 +12,15 @@
<body>
<div class="root">
<h1>ahriman
<img src="https://img.shields.io/badge/version-{{ version }}-informational" alt="{{ version }}">
<img src="https://img.shields.io/badge/architecture-{{ architecture }}-informational" alt="{{ architecture }}">
<img src="https://img.shields.io/badge/service%20status-{{ service.status }}-{{ service.status_color }}" alt="{{ service.status }}" title="{{ service.timestamp }}">
{% if authorized %}
<img src="https://img.shields.io/badge/version-{{ version }}-informational" alt="{{ version }}">
<img src="https://img.shields.io/badge/architecture-{{ architecture }}-informational" alt="{{ architecture }}">
<img src="https://img.shields.io/badge/service%20status-{{ service.status }}-{{ service.status_color }}" alt="{{ service.status }}" title="{{ service.timestamp }}">
{% endif %}
</h1>
{% include "login-form.jinja2" %}
{% include "login-form-hide.jinja2" %}
{% include "search-line.jinja2" %}
<section class="element">
@ -29,15 +33,21 @@
<th>status</th>
</tr>
{% for package in packages %}
{% if authorized %}
{% for package in packages %}
<tr class="package">
<td class="include-search"><a href="{{ package.web_url }}" title="{{ package.base }}">{{ package.base }}</a></td>
<td class="include-search">{{ package.packages|join("<br>"|safe) }}</td>
<td>{{ package.version }}</td>
<td>{{ package.timestamp }}</td>
<td class="status package-{{ package.status }}">{{ package.status }}</td>
</tr>
{% endfor %}
{% else %}
<tr class="package">
<td class="include-search"><a href="{{ package.web_url }}" title="{{ package.base }}">{{ package.base }}</a></td>
<td class="include-search">{{ package.packages|join("<br>"|safe) }}</td>
<td>{{ package.version }}</td>
<td>{{ package.timestamp }}</td>
<td class="status package-{{ package.status }}">{{ package.status }}</td>
<td colspan="100%">In order to see statuses you must login first</td>
</tr>
{% endfor %}
{% endif %}
</table>
</section>
@ -46,6 +56,17 @@
<li><a href="https://github.com/arcan1s/ahriman" title="sources">ahriman</a></li>
<li><a href="https://github.com/arcan1s/ahriman/releases" title="releases list">releases</a></li>
<li><a href="https://github.com/arcan1s/ahriman/issues" title="issues tracker">report a bug</a></li>
{% if auth_enabled %}
<li class="right">
{% if auth_username is not none %}
<form action="/logout" method="post">
<button class="login" type="submit">logout ({{ auth_username }})</button>
</form>
{% else %}
<button class="login" onclick="document.getElementById('login-form').style.display='block'">login</button>
{% endif %}
</li>
{% endif %}
</ul>
</footer>
</div>

View File

@ -0,0 +1,9 @@
<script>
const modal = document.getElementById('login-form');
window.onclick = function(event) {
if (event.target === modal) {
modal.style.display = "none";
}
}
</script>

View File

@ -0,0 +1,18 @@
{#idea is from here https://www.w3schools.com/howto/howto_css_login_form.asp#}
<div id="login-form" class="modal-login-form">
<form class="modal-login-form-content animate" action="/login" method="post">
<div class="login-container">
<label for="username"><b>username</b></label>
<input type="text" placeholder="enter username" name="username" required>
<label for="password"><b>password</b></label>
<input type="password" placeholder="enter password" name="password" required>
<button class="login" type="submit">login</button>
</div>
<div class="login-container">
<button class="cancel" onclick="document.getElementById('login-form').style.display='none'">cancel</button>
</div>
</form>
</div>

View File

@ -40,6 +40,7 @@
width: inherit;
}
/* table description */
th, td {
padding: 5px;
}
@ -103,6 +104,7 @@
background-color: rgba(var(--color-success), 1.0);
}
/* navigation footer description */
ul.navigation {
list-style-type: none;
margin: 0;
@ -115,11 +117,8 @@
float: left;
}
ul.navigation li.status {
display: block;
text-align: center;
text-decoration: none;
padding: 14px 16px;
ul.navigation li.right {
float: right;
}
ul.navigation li a {
@ -131,6 +130,86 @@
}
ul.navigation li a:hover {
background-color: rgba(var(--color-hover), 1.0);
opacity: 0.6;
}
/* login button in footer and modal page */
button.login {
background-color: rgba(var(--color-header), 1.0);
padding: 14px 16px;
border: none;
cursor: pointer;
width: 100%;
}
button.login:hover {
opacity: 0.6;
}
button.cancel {
background-color: rgba(var(--color-failed), 1.0);
padding: 14px 16px;
border: none;
cursor: pointer;
width: 100%;
}
button.cancel:hover {
opacity: 0.6;
}
/* modal page inputs and containers */
input[type=text], input[type=password] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}
.login-container {
padding: 14px 16px;
}
span.password {
float: right;
padding-top: 16px;
}
.modal-login-form {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4);
padding-top: 60px;
}
.modal-login-form-content {
background-color: #fefefe;
margin: 5% auto 15% auto;
border: 1px solid #888;
width: 25%;
}
/* modal page animation */
.animate {
-webkit-animation: animatezoom 0.6s;
animation: animatezoom 0.6s
}
@-webkit-keyframes animatezoom {
from {-webkit-transform: scale(0)}
to {-webkit-transform: scale(1)}
}
@keyframes animatezoom {
from {transform: scale(0)}
to {transform: scale(1)}
}
</style>