Implemented support for entitlements-based access control
If configured, anyone missing the required entitlement will now be denied access to the application and its api endpoints. If unset, any authenticated user is accepted.
This commit is contained in:
parent
a636f4f84a
commit
311ae0276e
@ -15,6 +15,7 @@ callback_path = '/auth'
|
||||
public_paths = [login_path, callback_path]
|
||||
user_cookie = 'username'
|
||||
token_cookie = 'token'
|
||||
access_cookie = 'access'
|
||||
permitted_format = re.compile('^[A-Za-z0-9-]+$')
|
||||
|
||||
config = ConfigParser()
|
||||
@ -23,6 +24,9 @@ config.read('./config.ini')
|
||||
app = Flask(__name__)
|
||||
oauth = Oauth(config['oauth'])
|
||||
app.wg = WireGuard(config['wireguard'])
|
||||
required_entitlement = config.get('security',
|
||||
'required_entitlement',
|
||||
fallback=None)
|
||||
|
||||
|
||||
@app.before_request
|
||||
@ -35,8 +39,19 @@ def setup() -> None:
|
||||
if not user_info:
|
||||
return Response(status=403)
|
||||
|
||||
remote_user = user_info['sub']
|
||||
app.wg.set_user(remote_user)
|
||||
if required_entitlement is None \
|
||||
or required_entitlement in user_info['entitlements']:
|
||||
remote_user = user_info['sub']
|
||||
app.wg.set_user(remote_user)
|
||||
return
|
||||
|
||||
response = Response(status=403)
|
||||
response.set_cookie(access_cookie,
|
||||
'denied',
|
||||
secure=True,
|
||||
samesite='Strict')
|
||||
return response
|
||||
|
||||
|
||||
@app.after_request
|
||||
def reload(response: Response) -> Response:
|
||||
|
@ -24,6 +24,15 @@ client_network = a.network.in.cidr/notation
|
||||
# Optional.
|
||||
server_extra_config = path/to/a/conf/fragment
|
||||
|
||||
|
||||
|
||||
[security]
|
||||
# The user entitlement (as read from the oauth token) to require
|
||||
# for users who are to be able to use the service.
|
||||
# Optional.
|
||||
required_entitlement = urn:mace:some:entitilement
|
||||
|
||||
|
||||
[oauth]
|
||||
authorization_url = https://oauth.example/authorize
|
||||
token_url = https://oauth.example/exchange
|
||||
|
@ -98,5 +98,13 @@
|
||||
</footer>
|
||||
</form>
|
||||
</template>
|
||||
<template id="access-denied">
|
||||
<div>
|
||||
<h2>Access denied</h2>
|
||||
<p>
|
||||
You do not have permission to access this site.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -16,6 +16,18 @@
|
||||
current.parentNode.removeChild(current);
|
||||
}
|
||||
|
||||
function deny_access() {
|
||||
const topbox = document.querySelector('topbox');
|
||||
while(topbox.firstChild) {
|
||||
topbox.removeChild(topbox.lastChild);
|
||||
}
|
||||
const placeholder = document.querySelector('placeholder');
|
||||
placeholder.replaceWith('');
|
||||
const template = document.querySelector('template#access-denied')
|
||||
.content.cloneNode(true);
|
||||
topbox.appendChild(template);
|
||||
}
|
||||
|
||||
function display_create_form() {
|
||||
const template = document.querySelector('template#create-form')
|
||||
.content.cloneNode(true);
|
||||
@ -167,21 +179,33 @@
|
||||
const request = new Request('/api' + path, data);
|
||||
const response = await fetch(request);
|
||||
if(response.status === 403) {
|
||||
console.log('doing login');
|
||||
const cookies = getCookies();
|
||||
const access = cookies['access'];
|
||||
if(access === 'denied') {
|
||||
throw new Error('access denied');
|
||||
}
|
||||
login();
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async function setupPage(route) {
|
||||
const configs = await make_api_request('GET', '/configs/');
|
||||
const cookies = getCookies();
|
||||
document.querySelector('user#banner-userid')
|
||||
.textContent = cookies['username'];
|
||||
document.querySelector('button#create-config')
|
||||
.addEventListener('click', (event) => {
|
||||
display_create_form();
|
||||
});
|
||||
await display_configs(...configs);
|
||||
try {
|
||||
const configs = await make_api_request('GET', '/configs/');
|
||||
const cookies = getCookies();
|
||||
document.querySelector('user#banner-userid')
|
||||
.textContent = cookies['username'];
|
||||
document.querySelector('button#create-config')
|
||||
.addEventListener('click', (event) => {
|
||||
display_create_form();
|
||||
});
|
||||
await display_configs(...configs);
|
||||
} catch(e) {
|
||||
if(e.message === 'access denied') {
|
||||
deny_access();
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
@ -65,6 +65,8 @@ topbox > button#create-config {
|
||||
|
||||
h2, summary {
|
||||
font-size: 1.5rem;
|
||||
font-weight: initial;
|
||||
margin: initial;
|
||||
}
|
||||
|
||||
configs {
|
||||
|
Loading…
x
Reference in New Issue
Block a user