2. OpenLDAP#
이 장은 openLDAP과 Altibase를 연동하는 방법을 설명한다.
OpenLDAP 소개#
OpenLDAP은 경량형 디렉터리 접근 프로토콜(Light-weight Directory Access Protocol, LDAP)을 오픈 소스로 구현한 것이다.
OpenLDAP은 backend 저장소로 RDBMS를 지원하는데 이를 SQL Backend 또는 back-sql이라고 한다. back-sql은 RDBMS와 연동시 ODBC를 사용한다.
OpenLDAP 설치#
-
Download OpenLDAP
http://www.openldap.org/ -
Unpack
$ tar xvfz name_of.tgz
-
Configure, Make, and Install
$ ./configure --prefix=.... --enable-sql ./configure --help 참조 $ make depend $ make $ make install (su root -c 'make install')
Altibase 설치#
Altibase는 6.5.1 이상을 설치할 것을 권장한다.
설치에 대한 자세한 설명은 Installation Guide를 참조한다.
메타 데이터 설정#
LDAP용 메타 테이블에 LDAP의 objectClass와 attributeType들을 Altibase의 어떤 테이블과 컬럼으로 매핑할 것인지 저장해야 한다.
Altibase는 4개의 LDAP용 메타 테이블을 설정하여 사용할 수 있다.
-
ldap_oc_mappings
-
ldap_attr_mappings
-
ldap_entries
-
ldap_entry_objclasses
ldap_oc_mappings#
objectClass 맵핑 테이블로써 structuralObjectClass와 테이블간의 관계를 저장한다.
컬럼 이름 | 설명 |
---|---|
ID | 고유 ID, 다른 ldap_* 테이블을 참조할 때 사용됨 |
NAME | objectClass 이름. slapd의 schema에 로딩된 objectClass 중 하나의 이름과 일치해야 함. |
KEYTBL | objectClass에 대응하는 테이블의 이름. 예제에서는 inetOrgPerson objectClass가 person 테이블로 맵핑됨 |
KEYCOL | "keytbl" 테이블의 primary key 컬럼의 이름 |
CREATE_PROC | 엔트리를 추가할 때 수행할 SQL 문 |
CREATE_KEYVAL | "CREATE_PROC" SQL 문으로 입력된 새로운 ID 값을 가져오는 쿼리문. 이 쿼리를 사용하려면 slapd.conf에서 create_needs_select를 "yes"로 설정해야 함. |
DELETE_PROC | 엔트리를 삭제할 때 수행할 SQL문 "keytbl.keycol"을 호스트 변수로 취한다. |
EXPECT_RETURN | CREATE_PROC과 DELETE_PROC의 SQL문이 리턴 값을 반환하는지 여부를 나타내는 비트열의 정수값. 첫 번째 비트는 ADD_PROC, 두 번째 비트는 DELETE_PROC에 해당한다. 사용 가능한 값: 0: CREATE_PROC과 DELETE_PROC의 SQL문 모두 리턴값이 없음 1: CREATE_PROC의 SQL문이 값을 반환함 2: DELETE_PROC의 SQL문이 값을 반환함 3: CREATE_PROC과 DELETE_PROC의 SQL문 모두 값을 반환함 리턴 값이 있는 SQL문(프로시저 또는 함수) 작성시 지켜야 할 사항: - CREATE_PROC의 리턴 값은 입력된 새로운 ID 값이어야 함. - DELETE_PROC의 리턴 값은 성공하면 0, 그렇지 않으면 1을 반환해야 함. - 리턴 값을 받는 outbinding 파라미터를 맨 앞에 위치시켜야 함. |
ldap_attr_mappings#
attributeType 맵핑 테이블로써 특정 objectClass를 위한 attributeType이 어떻게 SQL 문과 맵핑되는지를 저장한다.
컬럼 이름 | 설명 |
---|---|
ID | 고유 ID |
OC_MAP_ID | ldap_oc_mappings 테이블의 ID를 가리키며, 해당 attributeType이 어느 objectClass에 속하는지를 나타냄. |
NAME | attributeType의 이름. slapd의 schema에 로딩된 attributeType 중 하나의 이름과 일치해야 함. |
SEL_EXPR | 아래 attribute를 select 하기 위한 expression. ("select <sel_expr> from ..." 부분) |
FROM_TBLS | 아래 attribute를 가져올 테이블. ("select ... from <from_tbls > where ..." 부분) |
JOIN_WHERE | 아래 attribute를 select 하기 위한 조건. ("select ... where <join_where> ..." 부분) |
ADD_PROC | 해당 attribute에 입력하기 위한 SQL문. 추가될 attibute의 값과 그것에 연관된 엔트리의 "keytbl.keycol"을 호스트 변수로 취한다. |
DELETE_PROC | 해당 attribute에서 삭제하기 위한 SQL문. 삭제될 attibute의 값과 그것에 연관된 엔트리의 "keytbl.keycol" 을 호스트 변수로 취한다. |
PARAM_ORDER | ADD_PROC과 DELETE_PROC의 SQL문에서 keytbl.keycol 값이 attibute의 값보다 앞에 오는지 뒤에 오는지를 나타내는 비트열의 정수값. keytbl.keycol 값이 attibute의 값보다 앞에 오면 0, 뒤에 오면 1을 설정하면 된다. 첫 번째 비트는 ADD_PROC, 두 번째 비트는 DELETE_PROC에 해당한다. 사용 가능한 값: 0: CREATE_PROC과 DELETE_PROC의 SQL문 모두 keytbl.keycol 값이 attibute의 값보다 앞에 옴. 1: CREATE_PROC의 SQL문은 keytbl.keycol 값이 attibute의 값보다 뒤에 옴. 2: DELETE_PROC의 SQL문은 keytbl.keycol 값이 attibute의 값보다 뒤에 옴. 3: CREATE_PROC과 DELETE_PROC의 SQL문 모두 keytbl.keycol 값이 attibute의 값보다 뒤에 옴. |
EXPECT_RETURN | ADD_PROC과 DELETE_PROC의 SQL문이 리턴값을 반환하는지 여부를 나타내는 비트열의 정수값. 사용 가능한 값: 0: CREATE_PROC과 DELETE_PROC의 SQL문 모두 리턴값이 없음 1: CREATE_PROC의 SQL문이 값을 반환함 2: DELETE_PROC의 SQL문이 값을 반환함 3: CREATE_PROC과 DELETE_PROC의 SQL문 모두 값을 반환함 리턴값이 있는 SQL문(프로시저 또는 함수) 작성시 지켜야 할 사항: - CREATE_PROC과 DELETE_PROC의 리턴값은 성공하면 0, 그렇지 않으면 1을 반환해야 함. - 리턴값을 받는 outbinding 파라미터를 맨 앞에 위치시켜야 함. |
ldap_entries#
엔트리 맵핑 테이블이다. LDAP 트리의 각 엔트리를 식별할 수 있는 DN 값을 저장한다.
컬럼 이름 | 설명 |
---|---|
ID | 고유 ID |
DN | 엔트리의 DN이 "pretty" form으로 저장됨. |
OC_MAP_ID | 엔트리의 메인 objectClass에 해당하는 테이블의 ID. ldap_oc_mappings 테이블의 ID 값 중에 하나에 해당함. |
PARENT | 부모 엔트리의 ID. "suffix" 엔트리는 이 값이 0이다. |
KEYVAL | 엔트리의 데이터를 갖고 있는 테이블의 해당 로우의 primary key 컬럼의 값. 즉, 이 엔트리의 objectClass에 해당하는 테이블의 primary key 컬럼 값 ("keytbl.keycol" 값) |
ldap_entry_objclasses#
objectClass 맵핑 테이블이다. 엔트리가 어떤 보조 objectClass(auxiliary objectClasses)를 가지는지를 저장한다.
컬럼 이름 | 설명 |
---|---|
ENTRY_ID | ldap_entries.id의 값 |
NAME | auxiliary objectClass의 이름. slapd의 schema에 로딩된 objectClass 중 하나의 이름과 일치해야 함. |
환경 설정#
OpenLDAP 환경 설정을 위해 ODBC 설정 및 slapd.conf 파일을 편집한다.
.odbc.ini#
[ldap_altibase]
Description = ODBC for Altibase
Driver = /home/altibase/altibase_home/lib/libaltibase_odbc-64bit-ul64.so
server = 127.0.0.1
port = 20030
odbc 추적 설정: back-end 오류 발생시 문제 추적을 위해 아래의 설정을 이용할 수 있다.
.odbcinst.ini#
[ODBC]
TraceFile = /home/altibase/odbc.log
Trace = Yes
slapd.conf#
Altibase용 샘플로 제공된 slapd.conf을 참고하여 slapd.conf를 편집한다.
# $OpenLDAP$
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
# Define global ACLs to disable default read access.
# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral ldap://root.openldap.org
pidfile /usr/local/var/slapd.pid
argsfile /usr/local/var/slapd.args
#######################################################################
# sql database definitions
#######################################################################
database sql
suffix "dc=example,dc=com"
rootdn "cn=Manager,dc=example,dc=com"
rootpw secret
dbname ldap_altibase --ODBC dsn 이름
dbuser ldap --Altibase 사용자 이름
dbpasswd ldap --db 사용자 pw
subtree_cond "upper(ldap_entries.dn) LIKE CONCAT('%',upper(?))"
insentry_stmt "insert into ldap_entries (id,dn,oc_map_id,parent,keyval) values (ldap_entry_ids.nextval,?,?,?,?)"
has_ldapinfo_dn_ru no
upper_func UPPER
예제#
아래 그림과 같은 DIT(Directory Information Tree)를 RDBMS인 Altibase에 구축한다.
root DN은 dc=example,dc=com이며, ldif (LDAP Data Interchange Files, 트리 데이터를 텍스트로 표현한 파일)는 아래와 같다. root DN "dc=example,dc=com" 외에는 샘플 파일을 참고하기 바란다. 샘플 파일은 https://github.com/ALTIBASE/openldap/tree/master/servers/slapd/back-sql/rdbms_depend/altibase 에 있다.
# Mitya Kovalev, example.com
dn: cn=Mitya Kovalev,dc=example,dc=com
objectClass: inetOrgPerson
cn: Mitya Kovalev
sn: Kovalev
seeAlso: documentTitle=book1,dc=example,dc=com
seeAlso: documentTitle=book2,dc=example,dc=com
givenName: Mitya
userPassword:: bWl0
telephoneNumber: 222-3234
telephoneNumber: 332-2334
# Akakiy Zinberstein, example.com
dn: cn=Akakiy Zinberstein,dc=example,dc=com
objectClass: inetOrgPerson
cn: Akakiy Zinberstein
sn: Zinberstein
givenName: Akakiy
# Torvlobnor Puzdoy, example.com
dn: cn=Torvlobnor Puzdoy,dc=example,dc=com
objectClass: inetOrgPerson
cn: Torvlobnor Puzdoy
sn: Puzdoy
seeAlso: documentTitle=book1,dc=example,dc=com
givenName: Torvlobnor
telephoneNumber: 545-4563
# book1, example.com
dn: documentTitle=book1,dc=example,dc=com
objectClass: document
description: abstract1
documentTitle: book1
documentAuthor: cn=Mitya Kovalev,dc=example,dc=com
documentAuthor: cn=Torvlobnor Puzdoy,dc=example,dc=com
documentIdentifier: document 1
# book2, example.com
dn: documentTitle=book2,dc=example,dc=com
objectClass: document
description: abstract2
documentTitle: book2
documentAuthor: cn=Mitya Kovalev,dc=example,dc=com
documentIdentifier: document 2
# example.com
dn: dc=example,dc=com
objectClass: organization
objectClass: dcObject
o: Example
dc: example
이 엔트리는 structural objectClass "organization"과 auxiliary objectClass인 "dcObject"를 포함(contain)하며, 각각의 정의는 아래와 같다.
objectClass를 DB 테이블로 맵핑하기 위해서는 objectClass의 attribute member들 중에서 선택해서 컬럼화해야 한다. 이 예제에서는 "o"와 "dc" attribute를 선택했다.
objectclass ( 2.5.6.4 NAME 'organization'
DESC 'RFC2256: an organization'
SUP top STRUCTURAL
MUST o
MAY ( userPassword $ ... ) )
objectclass ( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
DESC 'RFC2247: domain component object'
SUP top AUXILIARY MUST dc )
아래는 위의 objectClass를 Altibase의 테이블로 맵핑한 "institutes" 테이블의 생성 구문과 데이터 삽입, 검색, 변경 등을 위한 메타 데이터를 생성하는 SQL문이다.
CREATE TABLE institutes (
id int NOT NULL,
name varchar(255)
);
insert into institutes (id,name) values (institute_ids.nextval,'Example');
insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,delete_proc,expect_return)
values (3,'organization','institutes','id','exec create_org(?)','exec delete_org(?)',1);
insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return)
values (11,3,'o','institutes.name','institutes',NULL,'exec set_org_name(?,?)',NULL,0,0);
insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return)
values (12,3,'dc','lower(institutes.name)','institutes,ldap_entries dcObject,ldap_entry_objclasses auxObjectClass',
'institutes.id=dcObject.keyval AND dcObject.oc_map_id=3 AND dcObject.id=auxObjectClass.entry_id AND auxObjectClass.oc_name=''dcObject''',
NULL,NULL,0,0);
insert into ldap_entries (id,dn,oc_map_id,parent,keyval)
values (ldap_entry_ids.nextval,'dc=example,dc=com',3,0,1); -- id = 1
insert into ldap_entry_objclasses (entry_id,oc_name) values (1,'dcObject');
CREATE OR REPLACE PROCEDURE create_org(keyval OUT INTEGER) AS
BEGIN
INSERT INTO institutes (id,name) VALUES (institute_ids.nextval,' ');
SELECT institute_ids.currval INTO keyval FROM DUAL;
END;
/
CREATE OR REPLACE PROCEDURE delete_org(keyval IN INTEGER) AS
BEGIN
DELETE FROM institutes WHERE id=keyval;
END;
/
CREATE OR REPLACE PROCEDURE set_org_name(keyval IN INTEGER, new_name IN varchar(255)) AS
BEGIN
UPDATE institutes SET name=new_name WHERE id=keyval;
END;
/
위 샘플 예제는 스크립트 파일로 제공되며, 아래와 같이 샘플 데이터를 구축할 수 있다. 사용된 스크립트 파일은 https://github.com/ALTIBASE/openldap/tree/master/servers/slapd/back-sql/rdbms_depend/altibase에서 다운로드할 수 있다.
ldap 사용자 생성#
sys 유저로 isql 접속 후 아래 SQL 문 실행
drop user ldap cascade;
create user ldap identified by ldap;
데이터 생성#
$ isql -s localhost -u ldap -p ldap -f backsql_create.sql
$ isql -s localhost -u ldap -p ldap -f testdb_create.sql
$ isql -s localhost -u ldap -p ldap -f testdb_metadata.sql
$ isql -s localhost -u ldap -p ldap -f testdb_data.sql
-
backsql_create.sql: 맵핑용 메타 데이터 저장을 위한 테이블 생성
-
testdb_create.sql: 사용할 objectClass를 DB 테이블로 생성
-
testdb_metadata.sql:맵핑용 메타데이터 입력
-
testdb_data.sql: objectClass 데이터 입력