티스토리 뷰

Flask-simpleldap

  • flask 기초 지식 필요.
  • ldap 기초 지식 필요.

기존에 Flask 를 통해 oauth2 인증이 없는 restfulAPI 서비스를 개발해서 사용하고 있었는데, 직원들의 로그인을 위해서, 로그인 기능을 구현하려다가 사내 NAS에 LDAP 서비스를 사용하고 있음을 확인하고 즉시 LDAP 에 인증을 통해, 사용하기로 하였네요.

간단하게 LDAP 인증을 하는 과정만 기록하는 정도로만…

검색

flask 에는 많은 확장 패키지를 제공하기 때문에 있을거 같아 검색을 해보니, 여러개의 LDAP 관련 확장 패키지들이 있었습니다. 프로젝트 구조부터, 환경 설정 까지.. 친절하게 설명된 블로그들.

저는 단순하게 인증 만 사용하고 사용자의 정보는 데이터베이스에 저장할게 아니라서, 복잡한건 필요가 없어 제일 단순해보이는 flask-simpleldap 를 사용하기로 결정했습니다.

라이센스도 MIT고, 저는 그냥 인증만 하면되니까요 ㅎㅎ

설치

저는 파이썬 3.6 을 사용합니다. 그래서 pip3 명령어를 사용해 설치는 하려고 하는데, openldap 라이브러리에 있는 헤더를 못찾는다고 하네요. 그래서 검색해보니 다음과 같이 설치하라고 합니다.

?> yum install openldap-devel

저는 centos 만 쓸줄 압니다.ㅜㅜ

하여튼, 테스트를 위해서 클라이언트 프로그램도 설치하였습니다.

?> yum install openldap-client

그리고 다시 설치를 시도하니 잘 됩니다.

?> pip3 install flask-simpleldap

설정

우선 이미 사용하고 있는 flask 서비스에 config 환경을 파이썬 파일로 빼놓은 상태입니다.

어떤거냐 하면은, 같은 폴더 안에 아래와 같이 2개의 파일이 있어요

  • app.py
  • config.py

config.py 에는 아래처럼 설정이 되어 있어요:

# Statement for enabling the development environment
DEBUG = True

# Define the application directory
BASE_DIR = os.path.abspath(os.path.dirname(__file__))

# Define the database - we are working with
# SQLite for this example
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, 'app.db')
DATABASE_CONNECT_OPTIONS = {}

# Application threads. A common general assumption is
# using 2 per available processor cores - to handle
# incoming requests using one and performing background
# operations using the other.
THREADS_PER_PAGE = 2

SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_POOL_RECYCLE = 1

그리고 app.py 에서 이렇게 사용해요:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config.from_object('config')

db = SQLAlchemy(app)

app.config.from_object('config')config.py 파일로부터 설정 옵션값들을 읽어와 app 에 적용합니다.

뭐 이런 상태입니다.

그래서 app.py 에 from flask_simpleldap import LDAP 를 추가하고, sqlalchemy 적용 한 다음에 ldap를 적용했습니다.

...

db = SQLAlchemy(app)

ldap = LDAP(app)

그러면 config.py 에 ldap 연동을 하기 위한 설정을 해보겠습니다.

설정하기에 앞서 저는 openldap 을 사용할 겁니다. 문서를 보니 openldap은 아래의 옵션들이 반드시 필요 합니다.

# LDAP configure
LDAP_REALM_NAME = 'OpenLDAP Authentication'
LDAP_HOST = 'LDAP 주소(IP, domain)' #프로토콜은 명시하지 않아도 돼요.
LDAP_PORT = 389 #기본값입니다.
LDAP_BASE_DN = 'dc=test,dc=co,dc=kr' # 기본, 도메인 이름 영역 LDAP 서버에서 확인할 수 있어요.
LDAP_USERNAME = 'uid=admin,cn=users,dc=test,dc=co,dc=kr' # 관리자 권한이 있는 계정으로 해야할거예요.
LDAP_PASSWORD = 'password' # 위 계정의 비밀번호입니다.

LDAP_OBJECTS_DN = 'dn' # LDAP 서버에서 확인할 수 있어요.
LDAP_OPENLDAP = True # 이거를 명시해줘야합니다. 저는 OpenLDAP 라이브러리를 사용할거예요.
LDAP_USER_OBJECT_FILTER = '(&(objectclass=inetOrgPerson)(uid=%s))' # 이게 꼭 필요합니다. uid 는 인증하려는 사용자의 계정 도메인영역인데요. 이게 없으면, 로그인하지 못해요. 여러분이 사용하고 있는 LDAP 서버에서 사용자 계정이 `uid` 가 아닌 다른것으로 되어 있을 수 있어요.

이렇게 설정하고 flask 를 실행해서 오류가 없으면 일단은 해결되었습니다.

그럼 라우팅을 설정하고 로그인 처리를 비슷하게 해보겠습니다.

옵션을 살펴보니 flask template 을 사용해서 로그인 폼을 제공하도록 할 수 있는거 같은데, 저는 그냥

POST로 json body에 id와 pw 만 받아서 인증 처리 과정을 작성했습니다.

아래의 내용은 app.py 마지막에 넣으면 됩니다.


...
from flask import request

@app.route('/ldap/auth')
def login_from_ldap():
  req = request.get_json()
  id = req['id']
  pw = req['pw']

  ret = ldap.bind_user(id, pw)

  if ret == True:
    return 'Success!'
  else:
    return 'False'

이런식으로 인증을 LDAP 로부터 할 수 있습니다. 그리고 인증이 되면, 사용자 정보를 ldap.get_object_details(id) 메서드를 이용해 가져올 수 있습니다.

참고로, 사용자 정보를 가져오면, 문자열이 bytes type 이기 때문에, utf-8로 decoding 해서 사용하셔야합니다.

-끝-