콘텐츠로 이동

2. OpenLDAP#

이 장은 openLDAP과 Altibase를 연동하는 방법을 설명한다.

OpenLDAP 소개#

OpenLDAP은 경량형 디렉터리 접근 프로토콜(Light-weight Directory Access Protocol, LDAP)을 오픈 소스로 구현한 것이다.

OpenLDAP은 backend 저장소로 RDBMS를 지원하는데 이를 SQL Backend 또는 back-sql이라고 한다. back-sql은 RDBMS와 연동시 ODBC를 사용한다.

OpenLDAP 설치#

  1. Download OpenLDAP
    http://www.openldap.org/

  2. Unpack

    $ tar xvfz name_of.tgz
    
  3. 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에 구축한다.

openldap_dit

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 데이터 입력