feat(api): ldap and OAuth2.0

This commit is contained in:
pycook 2023-12-14 19:49:31 +08:00
parent 21bc6631f9
commit e7dfe6c573
7 changed files with 31 additions and 13 deletions

View File

@ -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失效(尝试一下退出重新登录)"

View File

@ -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')

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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:

View File

@ -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