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):
|
||||
login_succeed = "登录成功"
|
||||
ldap_connection_failed = "连接LDAP服务失败"
|
||||
invalid_password = "密码验证失败"
|
||||
auth_only_with_app_token_failed = "应用 Token验证失败"
|
||||
session_invalid = "您不是应用管理员 或者 session失效(尝试一下退出重新登录)"
|
||||
|
|
|
@ -93,6 +93,9 @@ def _auth_with_token():
|
|||
|
||||
|
||||
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
|
||||
key = request.values.get('_key')
|
||||
secret = request.values.get('_secret')
|
||||
|
|
|
@ -57,7 +57,7 @@ def login():
|
|||
if request.args.get('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")
|
||||
user = UserCache.get(username)
|
||||
login_user(user)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import uuid
|
||||
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask import session
|
||||
from ldap3 import ALL
|
||||
|
@ -10,20 +11,25 @@ from ldap3 import Connection
|
|||
from ldap3 import Server
|
||||
from ldap3.core.exceptions import LDAPBindError
|
||||
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.resp_format import ErrFormat
|
||||
from api.models.acl import User
|
||||
|
||||
|
||||
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:
|
||||
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:
|
||||
who = current_app.config['LDAP'].get('ldap_user_dn').format(username)
|
||||
email = "{}@{}".format(who, current_app.config['LDAP'].get('ldap_domain'))
|
||||
who = config['LDAP'].get('ldap_user_dn').format(username)
|
||||
email = "{}@{}".format(who, config['LDAP'].get('ldap_domain'))
|
||||
|
||||
username = username.split('@')[0]
|
||||
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)
|
||||
except LDAPBindError:
|
||||
conn = Connection(server,
|
||||
user=f"{username}@{current_app.config['LDAP'].get('ldap_domain')}",
|
||||
user=f"{username}@{config['LDAP'].get('ldap_domain')}",
|
||||
password=password,
|
||||
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)
|
||||
|
||||
return user, True
|
||||
|
||||
except LDAPBindError as e:
|
||||
current_app.logger.info(e)
|
||||
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({
|
||||
'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'],
|
||||
'scope': ' '.join(config['scopes'] or []),
|
||||
'state': session[f'{auth_type.lower()}_state'],
|
||||
|
@ -50,7 +50,7 @@ def callback(auth_type):
|
|||
auth_type = auth_type.upper()
|
||||
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'):
|
||||
return abort(401, "state is invalid")
|
||||
|
@ -63,7 +63,7 @@ def callback(auth_type):
|
|||
'client_secret': config['client_secret'],
|
||||
'code': request.values['code'],
|
||||
'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'})
|
||||
if response.status_code != 200:
|
||||
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')
|
||||
"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()
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ from flask import session
|
|||
from flask_login import login_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_validate
|
||||
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")
|
||||
password = request.values.get("password")
|
||||
_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
|
||||
user, authenticated = authenticate_with_ldap(username, password)
|
||||
else:
|
||||
|
|
|
@ -2,7 +2,7 @@ version: '3.5'
|
|||
|
||||
services:
|
||||
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
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
|
@ -22,7 +22,7 @@ services:
|
|||
- '23306:3306'
|
||||
|
||||
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
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
|
|
Loading…
Reference in New Issue