mirror of https://github.com/veops/cmdb.git
feat(api): ldap and OAuth2.0
This commit is contained in:
parent
21bc6631f9
commit
e7dfe6c573
|
@ -5,6 +5,7 @@ from api.lib.resp_format import CommonErrFormat
|
||||||
|
|
||||||
class ErrFormat(CommonErrFormat):
|
class ErrFormat(CommonErrFormat):
|
||||||
login_succeed = "登录成功"
|
login_succeed = "登录成功"
|
||||||
|
ldap_connection_failed = "连接LDAP服务失败"
|
||||||
invalid_password = "密码验证失败"
|
invalid_password = "密码验证失败"
|
||||||
auth_only_with_app_token_failed = "应用 Token验证失败"
|
auth_only_with_app_token_failed = "应用 Token验证失败"
|
||||||
session_invalid = "您不是应用管理员 或者 session失效(尝试一下退出重新登录)"
|
session_invalid = "您不是应用管理员 或者 session失效(尝试一下退出重新登录)"
|
||||||
|
|
|
@ -93,6 +93,9 @@ def _auth_with_token():
|
||||||
|
|
||||||
|
|
||||||
def _auth_with_ip_white_list():
|
def _auth_with_ip_white_list():
|
||||||
|
if request.url.endswith("acl/users/info"):
|
||||||
|
return False
|
||||||
|
|
||||||
ip = request.headers.get('X-Real-IP') or request.remote_addr
|
ip = request.headers.get('X-Real-IP') or request.remote_addr
|
||||||
key = request.values.get('_key')
|
key = request.values.get('_key')
|
||||||
secret = request.values.get('_secret')
|
secret = request.values.get('_secret')
|
||||||
|
|
|
@ -57,7 +57,7 @@ def login():
|
||||||
if request.args.get('ticket'):
|
if request.args.get('ticket'):
|
||||||
|
|
||||||
if validate(request.args['ticket']):
|
if validate(request.args['ticket']):
|
||||||
redirect_url = session.get("next") or config.get("cas_after_login")
|
redirect_url = session.get("next") or config.get("cas_after_login") or "/"
|
||||||
username = session.get("CAS_USERNAME")
|
username = session.get("CAS_USERNAME")
|
||||||
user = UserCache.get(username)
|
user = UserCache.get(username)
|
||||||
login_user(user)
|
login_user(user)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from flask import abort
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from flask import session
|
from flask import session
|
||||||
from ldap3 import ALL
|
from ldap3 import ALL
|
||||||
|
@ -10,20 +11,25 @@ from ldap3 import Connection
|
||||||
from ldap3 import Server
|
from ldap3 import Server
|
||||||
from ldap3.core.exceptions import LDAPBindError
|
from ldap3.core.exceptions import LDAPBindError
|
||||||
from ldap3.core.exceptions import LDAPCertificateError
|
from ldap3.core.exceptions import LDAPCertificateError
|
||||||
|
from ldap3.core.exceptions import LDAPSocketOpenError
|
||||||
|
|
||||||
|
from api.lib.common_setting.common_data import AuthenticateDataCRUD
|
||||||
|
from api.lib.common_setting.const import AuthenticateType
|
||||||
from api.lib.perm.acl.audit import AuditCRUD
|
from api.lib.perm.acl.audit import AuditCRUD
|
||||||
from api.lib.perm.acl.resp_format import ErrFormat
|
from api.lib.perm.acl.resp_format import ErrFormat
|
||||||
from api.models.acl import User
|
from api.models.acl import User
|
||||||
|
|
||||||
|
|
||||||
def authenticate_with_ldap(username, password):
|
def authenticate_with_ldap(username, password):
|
||||||
server = Server(current_app.config.get('LDAP').get('ldap_server'), get_info=ALL, connect_timeout=3)
|
config = AuthenticateDataCRUD(AuthenticateType.CAS).get()
|
||||||
|
|
||||||
|
server = Server(config.get('LDAP').get('ldap_server'), get_info=ALL, connect_timeout=3)
|
||||||
if '@' in username:
|
if '@' in username:
|
||||||
email = username
|
email = username
|
||||||
who = current_app.config['LDAP'].get('ldap_user_dn').format(username.split('@')[0])
|
who = config['LDAP'].get('ldap_user_dn').format(username.split('@')[0])
|
||||||
else:
|
else:
|
||||||
who = current_app.config['LDAP'].get('ldap_user_dn').format(username)
|
who = config['LDAP'].get('ldap_user_dn').format(username)
|
||||||
email = "{}@{}".format(who, current_app.config['LDAP'].get('ldap_domain'))
|
email = "{}@{}".format(who, config['LDAP'].get('ldap_domain'))
|
||||||
|
|
||||||
username = username.split('@')[0]
|
username = username.split('@')[0]
|
||||||
user = User.query.get_by_username(username)
|
user = User.query.get_by_username(username)
|
||||||
|
@ -35,7 +41,7 @@ def authenticate_with_ldap(username, password):
|
||||||
conn = Connection(server, user=who, password=password, auto_bind=AUTO_BIND_NO_TLS)
|
conn = Connection(server, user=who, password=password, auto_bind=AUTO_BIND_NO_TLS)
|
||||||
except LDAPBindError:
|
except LDAPBindError:
|
||||||
conn = Connection(server,
|
conn = Connection(server,
|
||||||
user=f"{username}@{current_app.config['LDAP'].get('ldap_domain')}",
|
user=f"{username}@{config['LDAP'].get('ldap_domain')}",
|
||||||
password=password,
|
password=password,
|
||||||
auto_bind=AUTO_BIND_NO_TLS)
|
auto_bind=AUTO_BIND_NO_TLS)
|
||||||
|
|
||||||
|
@ -51,6 +57,11 @@ def authenticate_with_ldap(username, password):
|
||||||
user = UserCRUD.add(username=username, email=email, password=uuid.uuid4().hex)
|
user = UserCRUD.add(username=username, email=email, password=uuid.uuid4().hex)
|
||||||
|
|
||||||
return user, True
|
return user, True
|
||||||
|
|
||||||
except LDAPBindError as e:
|
except LDAPBindError as e:
|
||||||
current_app.logger.info(e)
|
current_app.logger.info(e)
|
||||||
return user, False
|
return user, False
|
||||||
|
|
||||||
|
except LDAPSocketOpenError as e:
|
||||||
|
current_app.logger.info(e)
|
||||||
|
return abort(403, ErrFormat.ldap_connection_failed)
|
||||||
|
|
|
@ -36,7 +36,7 @@ def login(auth_type):
|
||||||
|
|
||||||
qs = urlencode({
|
qs = urlencode({
|
||||||
'client_id': config['client_id'],
|
'client_id': config['client_id'],
|
||||||
'redirect_uri': url_for('oauth2.callback', _external=True),
|
'redirect_uri': url_for('oauth2.callback', auth_type=auth_type.lower(), _external=True),
|
||||||
'response_type': current_app.config[f'{auth_type}_RESPONSE_TYPE'],
|
'response_type': current_app.config[f'{auth_type}_RESPONSE_TYPE'],
|
||||||
'scope': ' '.join(config['scopes'] or []),
|
'scope': ' '.join(config['scopes'] or []),
|
||||||
'state': session[f'{auth_type.lower()}_state'],
|
'state': session[f'{auth_type.lower()}_state'],
|
||||||
|
@ -50,7 +50,7 @@ def callback(auth_type):
|
||||||
auth_type = auth_type.upper()
|
auth_type = auth_type.upper()
|
||||||
config = AuthenticateDataCRUD(auth_type).get()
|
config = AuthenticateDataCRUD(auth_type).get()
|
||||||
|
|
||||||
redirect_url = session.get("next") or config.get('after_login')
|
redirect_url = session.get("next") or config.get('after_login') or '/'
|
||||||
|
|
||||||
if request.values['state'] != session.get(f'{auth_type.lower()}_state'):
|
if request.values['state'] != session.get(f'{auth_type.lower()}_state'):
|
||||||
return abort(401, "state is invalid")
|
return abort(401, "state is invalid")
|
||||||
|
@ -63,7 +63,7 @@ def callback(auth_type):
|
||||||
'client_secret': config['client_secret'],
|
'client_secret': config['client_secret'],
|
||||||
'code': request.values['code'],
|
'code': request.values['code'],
|
||||||
'grant_type': current_app.config[f'{auth_type}_GRANT_TYPE'],
|
'grant_type': current_app.config[f'{auth_type}_GRANT_TYPE'],
|
||||||
'redirect_uri': url_for('oauth2.callback', _external=True),
|
'redirect_uri': url_for('oauth2.callback', auth_type=auth_type.lower(), _external=True),
|
||||||
}, headers={'Accept': 'application/json'})
|
}, headers={'Accept': 'application/json'})
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
current_app.logger.error(response.text)
|
current_app.logger.error(response.text)
|
||||||
|
@ -123,7 +123,7 @@ def logout(auth_type):
|
||||||
f'{auth_type}_state' in session and session.pop(f'{auth_type}_state')
|
f'{auth_type}_state' in session and session.pop(f'{auth_type}_state')
|
||||||
"next" in session and session.pop("next")
|
"next" in session and session.pop("next")
|
||||||
|
|
||||||
redirect_url = url_for('oauth2.login', _external=True, next=request.referrer)
|
redirect_url = url_for('oauth2.login', auth_type=auth_type, _external=True, next=request.referrer)
|
||||||
|
|
||||||
logout_user()
|
logout_user()
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ from flask import session
|
||||||
from flask_login import login_user
|
from flask_login import login_user
|
||||||
from flask_login import logout_user
|
from flask_login import logout_user
|
||||||
|
|
||||||
|
from api.lib.common_setting.common_data import AuthenticateDataCRUD
|
||||||
|
from api.lib.common_setting.const import AuthenticateType
|
||||||
from api.lib.decorator import args_required
|
from api.lib.decorator import args_required
|
||||||
from api.lib.decorator import args_validate
|
from api.lib.decorator import args_validate
|
||||||
from api.lib.perm.acl.acl import ACLManager
|
from api.lib.perm.acl.acl import ACLManager
|
||||||
|
@ -36,7 +38,8 @@ class LoginView(APIView):
|
||||||
username = request.values.get("username") or request.values.get("email")
|
username = request.values.get("username") or request.values.get("email")
|
||||||
password = request.values.get("password")
|
password = request.values.get("password")
|
||||||
_role = None
|
_role = None
|
||||||
if current_app.config.get('LDAP', {}).get('enabled'):
|
config = AuthenticateDataCRUD(AuthenticateType.LDAP).get()
|
||||||
|
if config.get('LDAP', {}).get('enabled'):
|
||||||
from api.lib.perm.authentication.ldap import authenticate_with_ldap
|
from api.lib.perm.authentication.ldap import authenticate_with_ldap
|
||||||
user, authenticated = authenticate_with_ldap(username, password)
|
user, authenticated = authenticate_with_ldap(username, password)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -2,7 +2,7 @@ version: '3.5'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
cmdb-db:
|
cmdb-db:
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/veops/cmdb-db:3.0
|
image: registry.cn-hangzhou.aliyuncs.com/veops/cmdb-db:2.3
|
||||||
container_name: cmdb-db
|
container_name: cmdb-db
|
||||||
environment:
|
environment:
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
|
@ -22,7 +22,7 @@ services:
|
||||||
- '23306:3306'
|
- '23306:3306'
|
||||||
|
|
||||||
cmdb-cache:
|
cmdb-cache:
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/veops/cmdb-cache:3.0
|
image: registry.cn-hangzhou.aliyuncs.com/veops/cmdb-cache:2.3
|
||||||
container_name: cmdb-cache
|
container_name: cmdb-cache
|
||||||
environment:
|
environment:
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
|
|
Loading…
Reference in New Issue