mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2025-06-14 12:06:06 +00:00
Resolve the conflicts and add adjustment to #591
This commit is contained in:
@ -62,6 +62,15 @@ class Setting(db.Model):
|
||||
'google_oauth_scope': 'openid email profile',
|
||||
'google_authorize_url': 'https://accounts.google.com/o/oauth2/v2/auth',
|
||||
'google_base_url': 'https://www.googleapis.com/oauth2/v3/',
|
||||
'azure_oauth_enabled': False,
|
||||
'azure_oauth_key': '',
|
||||
'azure_oauth_secret': '',
|
||||
'azure_oauth_scope': 'User.Read openid email profile',
|
||||
'azure_oauth_api_url': 'https://graph.microsoft.com/v1.0/',
|
||||
'azure_oauth_token_url':
|
||||
'https://login.microsoftonline.com/[tenancy]/oauth2/v2.0/token',
|
||||
'azure_oauth_authorize_url':
|
||||
'https://login.microsoftonline.com/[tenancy]/oauth2/v2.0/authorize',
|
||||
'oidc_oauth_enabled': False,
|
||||
'oidc_oauth_key': '',
|
||||
'oidc_oauth_secret': '',
|
||||
|
@ -696,6 +696,26 @@ def setting_authentication():
|
||||
'status': True,
|
||||
'msg': 'Saved successfully. Please reload PDA to take effect.'
|
||||
}
|
||||
elif conf_type == 'azure':
|
||||
Setting().set(
|
||||
'azure_oauth_enabled',
|
||||
True if request.form.get('azure_oauth_enabled') else False)
|
||||
Setting().set('azure_oauth_key',
|
||||
request.form.get('azure_oauth_key'))
|
||||
Setting().set('azure_oauth_secret',
|
||||
request.form.get('azure_oauth_secret'))
|
||||
Setting().set('azure_oauth_scope',
|
||||
request.form.get('azure_oauth_scope'))
|
||||
Setting().set('azure_oauth_api_url',
|
||||
request.form.get('azure_oauth_api_url'))
|
||||
Setting().set('azure_oauth_token_url',
|
||||
request.form.get('azure_oauth_token_url'))
|
||||
Setting().set('azure_oauth_authorize_url',
|
||||
request.form.get('azure_oauth_authorize_url'))
|
||||
result = {
|
||||
'status': True,
|
||||
'msg': 'Saved successfully. Please reload PDA to take effect.'
|
||||
}
|
||||
elif conf_type == 'oidc':
|
||||
Setting().set(
|
||||
'oidc_oauth_enabled',
|
||||
|
@ -25,10 +25,12 @@ from ..models.setting import Setting
|
||||
from ..models.history import History
|
||||
from ..services.google import google_oauth
|
||||
from ..services.github import github_oauth
|
||||
from ..services.azure import azure_oauth
|
||||
from ..services.oidc import oidc_oauth
|
||||
|
||||
google = None
|
||||
github = None
|
||||
azure = None
|
||||
oidc = None
|
||||
|
||||
index_bp = Blueprint('index',
|
||||
@ -41,9 +43,11 @@ index_bp = Blueprint('index',
|
||||
def register_modules():
|
||||
global google
|
||||
global github
|
||||
global azure
|
||||
global oidc
|
||||
google = google_oauth()
|
||||
github = github_oauth()
|
||||
azure = azure_oauth()
|
||||
oidc = oidc_oauth()
|
||||
|
||||
|
||||
@ -97,6 +101,20 @@ def github_login():
|
||||
return github.authorize_redirect(redirect_uri)
|
||||
|
||||
|
||||
@index_bp.route('/azure/login')
|
||||
def azure_login():
|
||||
if not Setting().get('azure_oauth_enabled') or azure is None:
|
||||
current_app.logger.error(
|
||||
'Microsoft OAuth is disabled or you have not yet reloaded the pda application after enabling.'
|
||||
)
|
||||
abort(400)
|
||||
else:
|
||||
redirect_uri = url_for('azure_authorized',
|
||||
_external=True,
|
||||
_scheme='https')
|
||||
return azure.authorize_redirect(redirect_uri)
|
||||
|
||||
|
||||
@index_bp.route('/oidc/login')
|
||||
def oidc_login():
|
||||
if not Setting().get('oidc_oauth_enabled') or oidc is None:
|
||||
@ -167,6 +185,44 @@ def login():
|
||||
login_user(user, remember=False)
|
||||
return redirect(url_for('index.index'))
|
||||
|
||||
if 'azure_token' in session:
|
||||
me = json.loads(azure.get('me').text)
|
||||
azure_username = me["userPrincipalName"]
|
||||
azure_givenname = me["givenName"]
|
||||
azure_familyname = me["surname"]
|
||||
if "email" in me:
|
||||
azure_email = me["email"]
|
||||
else:
|
||||
azure_email = ""
|
||||
if not azure_email:
|
||||
azure_email = me["userPrincipalName"]
|
||||
# Handle foreign principals such as guest users
|
||||
azure_email = re.sub(r"#.*$", "", azure_email)
|
||||
azure_username = re.sub(r"#.*$", "", azure_username)
|
||||
|
||||
user = User.query.filter_by(username=azure_username).first()
|
||||
if not user:
|
||||
user = User(username=azure_username,
|
||||
plain_text_password=None,
|
||||
firstname=azure_givenname,
|
||||
lastname=azure_familyname,
|
||||
email=azure_email)
|
||||
|
||||
result = user.create_local_user()
|
||||
if not result['status']:
|
||||
current_app.logger.warning('Unable to create ' + azure_username)
|
||||
session.pop('azure_token', None)
|
||||
# note: a redirect to login results in an endless loop, so render the login page instead
|
||||
return render_template('login.html',
|
||||
saml_enabled=SAML_ENABLED,
|
||||
error=('User ' + azure_username +
|
||||
' cannot be created.'))
|
||||
|
||||
session['user_id'] = user.id
|
||||
session['authentication_type'] = 'OAuth'
|
||||
login_user(user, remember=False)
|
||||
return redirect(url_for('index.index'))
|
||||
|
||||
if 'oidc_token' in session:
|
||||
me = json.loads(oidc.get('userinfo').text)
|
||||
oidc_username = me["preferred_username"]
|
||||
|
38
powerdnsadmin/services/azure.py
Normal file
38
powerdnsadmin/services/azure.py
Normal file
@ -0,0 +1,38 @@
|
||||
from flask import request, session, redirect, url_for, current_app
|
||||
|
||||
from .base import authlib_oauth_client
|
||||
from ..models.setting import Setting
|
||||
|
||||
|
||||
def azure_oauth():
|
||||
if not Setting().get('azure_oauth_enabled'):
|
||||
return None
|
||||
|
||||
def fetch_azure_token():
|
||||
return session.get('azure_token')
|
||||
|
||||
azure = authlib_oauth_client.register(
|
||||
'azure',
|
||||
client_id=Setting().get('azure_oauth_key'),
|
||||
client_secret=Setting().get('azure_oauth_secret'),
|
||||
api_base_url=Setting().get('azure_oauth_api_url'),
|
||||
request_token_url=None,
|
||||
access_token_url=Setting().get('azure_oauth_token_url'),
|
||||
authorize_url=Setting().get('azure_oauth_authorize_url'),
|
||||
client_kwargs={'scope': Setting().get('azure_oauth_scope')},
|
||||
fetch_token=fetch_azure_token,
|
||||
)
|
||||
|
||||
@current_app.route('/azure/authorized')
|
||||
def azure_authorized():
|
||||
session['azure_oauthredir'] = url_for('.azure_authorized',
|
||||
_external=True,
|
||||
_scheme='https')
|
||||
token = azure.authorize_access_token()
|
||||
if token is None:
|
||||
return 'Access denied: reason=%s error=%s' % (
|
||||
request.args['error'], request.args['error_description'])
|
||||
session['azure_token'] = (token)
|
||||
return redirect(url_for('.login', _external=True, _scheme='https'))
|
||||
|
||||
return azure
|
@ -52,6 +52,7 @@
|
||||
<li class="active"><a href="#tabs-ldap" data-toggle="tab">LDAP</a></li>
|
||||
<li><a href="#tabs-google" data-toggle="tab">Google OAuth</a></li>
|
||||
<li><a href="#tabs-github" data-toggle="tab">Github OAuth</a></li>
|
||||
<li><a href="#tabs-azure" data-toggle="tab">Microsoft OAuth</a></li>
|
||||
<li><a href="#tabs-oidc" data-toggle="tab">OpenID Connect OAuth</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
@ -359,6 +360,63 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="tabs-azure">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<form role="form" method="post" data-toggle="validator">
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
|
||||
<input type="hidden" value="azure" name="config_tab" />
|
||||
<fieldset>
|
||||
<legend>GENERAL</legend>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="azure_oauth_enabled" name="azure_oauth_enabled" class="checkbox" {% if SETTING.get('azure_oauth_enabled') %}checked{% endif %}>
|
||||
<label for="azure_oauth_enabled">Enable Microsoft Azure OAuth</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="azure_oauth_key">Client key</label>
|
||||
<input type="text" class="form-control" name="azure_oauth_key" id="azure_oauth_key" placeholder="Azure OAuth client ID" data-error="Please input Client key" value="{{ SETTING.get('azure_oauth_key') }}">
|
||||
<span class="help-block with-errors"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="azure_oauth_secret">Client secret</label>
|
||||
<input type="text" class="form-control" name="azure_oauth_secret" id="azure_oauth_secret" placeholder="Azure OAuth client secret" data-error="Please input Client secret" value="{{ SETTING.get('azure_oauth_secret') }}">
|
||||
<span class="help-block with-errors"></span>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>ADVANCE</legend>
|
||||
<div class="form-group">
|
||||
<label for="azure_oauth_scope">Scope</label>
|
||||
<input type="text" class="form-control" name="azure_oauth_scope" id="azure_oauth_scope" placeholder="e.g. email" data-error="Please input scope - e.g. User.Read" value="{{ SETTING.get('azure_oauth_scope') }}">
|
||||
<span class="help-block with-errors"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="azure_oauth_api_url">API URL</label>
|
||||
<input type="text" class="form-control" name="azure_oauth_api_url" id="azure_oauth_api_url" placeholder="e.g. https://graph.microsoft.com/v1.0/" data-error="Please input API URL" value="{{ SETTING.get('azure_oauth_api_url') }}">
|
||||
<span class="help-block with-errors"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="azure_oauth_token_url">Token URL</label>
|
||||
<input type="text" class="form-control" name="azure_oauth_token_url" id="azure_oauth_token_url" placeholder="e.g. https://login.microsoftonline.com/[tenancyID]/oauth2/v2.0/token" data-error="Please input Token URL" value="{{ SETTING.get('azure_oauth_token_url') }}">
|
||||
<span class="help-block with-errors"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="azure_oauth_authorize_url">Authorize URL</label>
|
||||
<input type="text" class="form-control" name="azure_oauth_authorize_url" id="azure_oauth_authorize_url" placeholder="e.g. https://login.microsoftonline.com/[tenancyID]/oauth2/v2.0/authorize" data-error="Please input Authorize URL" value="{{ SETTING.get('azure_oauth_authorize_url') }}">
|
||||
<span class="help-block with-errors"></span>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-flat btn-primary">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<legend>Help</legend>
|
||||
<p>Fill in all the fields in the left form.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="tabs-oidc">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
@ -618,6 +676,40 @@
|
||||
{% endif %}
|
||||
// END: Github tab js
|
||||
|
||||
// START: Azure tab js
|
||||
// update validation requirement when checkbox is togged
|
||||
$('#azure_oauth_enabled').iCheck({
|
||||
checkboxClass : 'icheckbox_square-blue',
|
||||
increaseArea : '20%'
|
||||
}).on('ifChanged', function(e) {
|
||||
var is_enabled = e.currentTarget.checked;
|
||||
if (is_enabled){
|
||||
$('#azure_oauth_key').prop('required', true);
|
||||
$('#azure_oauth_secret').prop('required', true);
|
||||
$('#azure_oauth_scope').prop('required', true);
|
||||
$('#azure_oauth_api_url').prop('required', true);
|
||||
$('#azure_oauth_token_url').prop('required', true);
|
||||
$('#azure_oauth_authorize_url').prop('required', true);
|
||||
} else {
|
||||
$('#azure_oauth_key').prop('required', false);
|
||||
$('#azure_oauth_secret').prop('required', false);
|
||||
$('#azure_oauth_scope').prop('required', false);
|
||||
$('#azure_oauth_api_url').prop('required', false);
|
||||
$('#azure_oauth_token_url').prop('required', false);
|
||||
$('#azure_oauth_authorize_url').prop('required', false);
|
||||
}
|
||||
});
|
||||
// init validation requirement at first time page load
|
||||
{% if SETTING.get('azure_oauth_enabled') %}
|
||||
$('#azure_oauth_key').prop('required', true);
|
||||
$('#azure_oauth_secret').prop('required', true);
|
||||
$('#azure_oauth_scope').prop('required', true);
|
||||
$('#azure_oauth_api_url').prop('required', true);
|
||||
$('#azure_oauth_token_url').prop('required', true);
|
||||
$('#azure_oauth_authorize_url').prop('required', true);
|
||||
{% endif %}
|
||||
// END: Azure tab js
|
||||
|
||||
// START: OIDC tab js
|
||||
$('#oidc_oauth_enabled').iCheck({
|
||||
checkboxClass : 'icheckbox_square-blue',
|
||||
|
@ -87,7 +87,7 @@
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
</form>
|
||||
{% if SETTING.get('google_oauth_enabled') or SETTING.get('github_oauth_enabled') or SETTING.get('oidc_oauth_enabled') %}
|
||||
{% if SETTING.get('google_oauth_enabled') or SETTING.get('github_oauth_enabled') or SETTING.get('oidc_oauth_enabled') or SETTING.get('azure_oauth_enabled') %}
|
||||
<div class="social-auth-links text-center">
|
||||
<p>- OR -</p>
|
||||
{% if SETTING.get('oidc_oauth_enabled') %}
|
||||
@ -102,9 +102,14 @@
|
||||
{% endif %}
|
||||
{% if SETTING.get('google_oauth_enabled') %}
|
||||
<a href="{{ url_for('index.google_login') }}" class="btn btn-block btn-social btn-google btn-flat"><i
|
||||
class="fa fa-google-plus"></i> Sign in using
|
||||
class="fa fa-google"></i> Sign in using
|
||||
Google</a>
|
||||
{% endif %}
|
||||
{% if SETTING.get('azure_oauth_enabled') %}
|
||||
<a href="{{ url_for('index.azure_login') }}" class="btn btn-block btn-social btn-microsoft btn-flat"><i
|
||||
class="fa fa-windows"></i> Sign in using
|
||||
Microsoft Azure</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
Reference in New Issue
Block a user