KOEI's Diary 위치로그  |  태그  |  방명록
짝프로그래밍 에 해당하는 글1 개
2007/01/10   Active Directory로 계정 정보 옮기기


Active Directory로 계정 정보 옮기기
개발이야기 | 2007/01/10 07:17
2007/01/10 07:17 2007/01/10 07:17
  • 발주처 : 한국xxx공제조합
  • Objective : Oracle에 있는 계정 정보를 Active Directory로 동기화 하자.
    • 작업대상은 300-400명
    • 그리고 시간은 몇 분 정도까지 허용
  • 추정시간 : 2-3일
  • 작업시간 :
    • 개발기간 2006.12.20 - 2006.12.23 (조사기간까지 포함하면 1주일 정도 소요),
    • 배치기간 2006.12.26
  • 작업인원 : Crazia, KOEI.
  • 작업환경 : VB.NET, Windows 2003
  • 반성 :
    • 작업추정이 극도로 잘못. 지나치게 낙관적
    • 짝프로그래밍의 높은 생산성을 체험
    • 배치 및 인수인계 준비가 부족했음.(애드립으로 해결 -_-v)
    • 새로운 영역에 대한 접근방법론을 제시

2006년 말에 했었던 결재관련시스템과 별도로 추가로 하게된 일. 최초에 주어진 미션과는 조금 다르게 되었지만(원래는 소스가 AS/400이었다.) 일을 시작할 때 추정과정에서 하루에서 이틀정도가 소요될 것으로 생각을 했으나, 그건 정말 말그대로 또 하나의 커다란 추정 실패였을뿐이다. (다시금 생각해봐도 2006년 거듭된 실패의 연속이었다. Crazia와의 짝프로그래밍이 성공적이지 않았다면 정말 끔찍한 연말이었을꺼다 -ㅅ-)

초기에 개발은 고객쪽의 요청(유지보수문제?)와 담당개발자(초기 KOEI 1人에서 Crazia 1人로 변경)의 언어선호로 C++로 개발을 하기로 했으나, 2인의 짝프로그래밍 체제로 가면서, agile한 개발방법론 주창을 한 K모군의 음모(그는 과연 agile의 A라도 제대로 알고 있었을까?) 로 VB.NET으로 변경. 추후에 VB.NET으로 개발을 하면 C++로 포팅을 하는 방향으로 가는 것으로 목표를 설정했다. 기존까지는 두 사람 다 Visual Basic이라고는 [Comparing Programming Languages in real life](언어를 여성에 빗대어 표현하고 있다.)과 비슷한 평가(She is little bitch)를 두 사람 다 내리고 있는 단계였다.(Basic의 평가 역시 크게 다르지 않다. 누구나 한번쯤은~) VB.NET을 초기개발언어(?)로 선정한 이유는 Active Directory를 제대로 파악하고 있는 사람이 없었고, 빠른 개발언어를 사용하고 싶었는데, VB.NET은 Microsoft에서 주도하는 언어이고, 이는 우리가 작업하고자 하는 영역에 많은 예제와 - 실제로 구글링시 많은 유용한 검색결과를 보여주었다. What are you expected? she is VB.- 쉬운 접근이 가능할거 같다는 기대치를 쉽게 채워주었기 때문이다. 또한 결재시스템 작업을 C#으로 하면서 .NET Framework에 대한 최소한의 이해도가 생겼고, 이는 VB.NET으로 작업하는데 있어서 문법적인 차이 이상은 새로운 것을 사용할 필요가 없었다.
(최초 고려대상은 perl이었다. XML-RPC기반의 Active Directory Bridge 구현과 같은 아름다운 기사도 찾아볼 수 있었고, 어찌되었건 Active Directory라는 녀석이 결국 LDAP이란 말이지 라는 놀라운 사실로 알려주었다. 다만 현재 개발자들에게 보다 친숙하고 편리한 개발환경 구축이 편이해야했고-최소한 디버깅 환경은 익숙해야했다.- 결정적으로 설치와 예제코드의 라인수에서 밀렸다. Perl누나는 다음 기회로 ㅠ.ㅠ)

작업은 처음 낙관적인 추정이 나온대로 간단했다.

  1. 작업 환경 설정
  2. 오라클에서 계정정보를 가져오기
  3. Active Directory에 해당 유저 정보 삽입 및 갱신

최초의 작업장벽은 테스트 환경 설치였고, 이는 Active Directory 및 Oracle 설치였는데, Oracle을 윈도우에 설치해본 경험이 전무해서 의외로 시간을 2일이라는 시간을 잡아먹었다. 할튼 설치를 하고 오라클에서 계정 정보를 가져오는 코드를 작성하는데도 하루의 시간이 걸렸다. ODP.NET을 활용했고 일반적인 예제와 토시 하나 다르지 않다 -ㅅ-.

' Set Connection String
Dim ConnectionString As String = "User Id=[userid];Password=[passwd];Data Source=[LISTENER];"

Dim con As OracleConnection = New OracleConnection()
' Create the OracleCommand object
Dim cmd As OracleCommand = New OracleCommand()

cmd.Connection = con
cmd.CommandType = CommandType.Text

Try
  ' Open the connection
  con.Open()
  Console.WriteLine("Connection to Oracle database established successfully !")
  Console.WriteLine(" ")

  Dim cmdQuery As String = _
       "SELECT 아이디 AS id, 표시이름 AS displayname, 부서 as dept, 상위부서 AS ascent_dept, 암호 AS userpasswd, 패스워드만료기한 as expired" & _
      "   FROM 테이블들" & _
       "  WHERE 조건"

  cmd.CommandText = cmdQuery

  ' Execute command, create OracleDataReader object
  Dim reader As OracleDataReader = cmd.ExecuteReader()

  Dim ADAcessor As ActiveDirectoryAddContacts.Class1 = New ActiveDirectoryAddContacts.Class1()

  Dim id As String
  Dim passwd As String = ""
  Dim displayname As String
  Dim description As String
  Dim expirePasswd As String

  While (reader.Read())
       id = reader("id")
       displayname = reader("displayname")
       description = displayname & "/" & reader("dept") & "/" & reader("ascent_dept")
       expirePasswd = reader("expired")
       If (False = reader.IsDBNull(4)) Then
           passwd = reader("userpasswd")
       Else
           Continue While
       End If

       Try
           ' Active Directory Processing
           ADAcessor.UpdateUser(id, displayname, passwd, description, expirePasswd)
       Catch ex As Exception
           Console.WriteLine(ex.ToString())
       End Try
  End While
Catch ex As Exception
    Console.WriteLine(ex.Message)
End Try



여튼 저튼 대부분의 시간은 작업환경을 설정하고, 새로운 문법에 살포시 발 담가보고(차라리 익숙한 C#으로 할 걸이라는 후회를 하기 시작했으나, C#만은 제발이라는 외부의 요청이 있었다. 포팅할껀데 하고 -ㅅ- 생각을 이때 했다면)  그리고 알려준 테이블 스키마와 예제데이터에서 관련 정보를 가져오는데 시간이 걸렸다.

Active Directory에 새로운 사용자를 추가하거나, 기존의 사용자 정보를 갱신하는 기본 코드는 다음과 같다.

' 현재 시스템의 Active Directory Path가져오기
Dim DSESearcher As System.DirectoryServices.DirectorySearcher = New System.DirectoryServices.DirectorySearcher()
Dim ADSPath As String = DSESearcher.SearchRoot.Path
ADSPath = ADSPath.Insert(7, "CN=Users,")

Dim oRoot As DirectoryEntry =  New DirectoryEntry(ADSPath, 어드민아이디, 어드민패스워드, AuthenticationTypes.Secure)

Try
    'Make sure this user is not already there.
    Dim oNewUser As DirectoryEntry = oRoot.Children.Find("sAMAccountName=유저아이디", "user")
    With oNewUser
        .Properties("displayName").Value = displayname
        .Properties("givenName").Value = displayname
        .Properties("description").Value = description
        .Invoke("SetPassword", passwd)
        .CommitChanges()
    End With
    Return
Catch oCOMException As System.Runtime.InteropServices.COMException
    'User is not in AD. So, add
    oNewUser = oRoot.Children.Add(string("cn={0}", displayname), "user")
    With oNewUser
        .Properties("sAMAccountName").Add(id)              ' Add/Specify more properties, if needed
        .Properties("displayName").Add(displayname)              ' Add/Specify more properties, if needed
        .Properties("givenName").Add(displayname)
        .Properties("description").Add(description)
        .Properties("name").Add(displayname)
        .Properties("userPrincipalName").Add(id & "@" & DomainName)

        .Properties("UserAccountControl").Value = .Properties("UserAccountControl").Value - 2
         .Invoke("SetPassword", passwd)               ' Now that the user is created, set the password

        .CommitChanges()
    End With
End Try

유저를 찾아보고 있으면 변경을 하고, 없으면 예외를 발생 시키니 그 예외처리로 새로운 유저를 추가하면 된다는 간단한 코드였다. 물론 Active Directory나 LDAP(Crazia은 LDAP에 대한 경험이 있으셨다고 하나 Active Directory에 대한 부분은 상황이 같았다.)에 대한 정보가 부족했기 때문에, User라는 DirectoryEntry가 가지는 속성값을 찍어보기 위한 디버깅 코드도 작성을 했어야했고(초기에는 MSDN을 찾았으나 제대로 된 정보를 찾지 못했다. 검색능력 부족.) cn과 sAMAccountName이 실제로 Active Directory에서 어떻게 표현이 되는지 하는 것을 찾고,  꽤 많은 시간을 보냈다.
가장 크게 고생했던 부분은, MSDN에서 정보를 찾고, 예제코드를 보아도 저 코드가 동작하지 않는 것이었다. 왜 그럴까? 우리가 작성한 코드에 문제가 있지 않을까 하고 디버깅과 코드 리뷰, 예제코드와 비교 등 끝임없이 삽질을 계속했다. 첫번째줄은 유저의 초기 설정값으로 다음번에 들어올 때 패스워드를 바꿔야함을 끄기위한 설정이었다. 두번째 줄은 말그대로 패스워드를 바꾸는 것이고.. 먼가 문제가 있는거 같아 단계별로 CommitChanges()를 호출해보기도 하고..
결국 문제의 원인은 계정생성 도중에 패스워드를 바꾸려고 했다는 것이었다.

With oNewUser
   .Properties("sAMAccountName").Add(id)
   .Properties("displayName").Add(displayname)
   .Properties("givenName").Add(displayname)
   .Properties("description").Add(description)
   .Properties("name").Add(displayname)
   .Properties("userPrincipalName").Add(id & "@" & DomainName)
   .CommitChanges()
End With

'now user is created, set the password
oNewUser = Nothing

oNewUser = oRoot.Children.Find(CNName, "user")
With oNewUser
    .Properties("UserAccountControl").Value = .Properties("UserAccountControl").Value - 2
    .Invoke("SetPassword", passwd)
    .CommitChanges()                                   ' Commit the changes again
End With

일단 패스워드 설정과 관련된 부분을 빼고 저장을 하고, 해당 유저를 찾아오는 코드를 추가하는 것을 추가하는 것(로그인을 하는 것과 같았다.)이 해결방법이 되겠다. 그 외에도 현재 Active Directory의 정책에서 최소패스워드길이라든지, 패스워드의 복잡도 설정으로 패스워드가 설정되지 않는 문제도 있었다. 겉으로 보기에는 아니 왜 됐다 안 됐다해? 여기서 짝프로그래밍의 장점이 나오는데, 만약 혼자 이 작업을 했다면 찾는 도중이라든지 예외를 보이는 도중에 분명히 잘 안되네 하고 IDLE 타임이 생겼을텐데 우리는 서로의 눈치를 보면서 끝없이 돌진 돌진 돌진했다. 그리고 그 과정은 힘들기는 했으나 토론을 하면서 진행하는 과정은 꽤 즐겁기도했다.

위 코드까지 작성을 하고 일단 작업을 마무리하고, 코드 정리를 하고 일을 끝냈다. 패스워드만료기한 설정은, Crazia 혼자 추후에 작업을 하는 것으로 하고 크리스마스 연휴를 조촐하게 보냈다. (암호만료기한 설정은 Crazia가 간단하게 해결을 했고, 추후에 고객이 필요없다는 얘기에 빠지게 되었다.) 여기까지 총 작업시간은 6시간이 걸렸다. 꽤 많이 헤매고 찾아본 것에 비해서는 빠르게 마무리가 되었다. (단연코 말하건데 위 작업을 혼자 했다면 찾아보고, 시도해보고 하면서 중간에 IDLE 타임 및 딴짓을 하면서 워킹데이로 5일 즉 1주일는 걸렸을꺼 같다. 그래 별로 실력없는 개발자 맞다.

크리스마스 연휴 이후에 실제 배치는 KOEI 담당이었고, 그날 겪었던 문제는 다음과 같다.

  • 사용자를 최초에 찾아오는 코드에서 sAMAccountName로는 사용자를 찾을 수 없다.
    => 개발하면서 cn(사용자관리화면에 표시되는 이름)과 sAMAccountName(실제로그인아이디)의 차이를 알아내고 이를 코드에 반영하면서 생긴 오류인듯 하고, 해당코드를 cn으로 고쳐서 해결을 봤다. ("sAMAccountName=유저아이디" => "cn=출력이름")
  • cn으로 고친다음에는 동명이인의 경우 추가되지 않는 문제가 생겼다.
    => 결국 표시되는 이름을 사용자 아이디로 수정했고, 고객의 요청사항에 따라 description에 사용자 이름을 기술하는 것으로 해결했다.
  • 한국xxx공제조합에서 담당자에게  유지보수를 위한 코드 설명, 개발툴 사용법을 인수인계해야했는데 Visual Studio 8.0을 라이센스 문제로 설치할 수 없었다.
    => .NET Framework SDK를 깔고 컴파일러 사용법을 알아보고 Editor등을 설정하고 하다가, SharpDevelop이라는 OpenSource 개발툴을 찾아서 해당 개발툴을 컴파일이 가능할 정도까지 같이 익히고 소스코드 리뷰를 했다.

해당 모든 일을 마무리하고 반성한 점은 지나치게 낙관적으로 일정추정을 했다. 만약 AS/400을 그대로 썼다고 했다면 이미 알고 있는 Oracle보다 더 많은 시간을 소요했고 개발환경 설정도 쉽지 않았을 것이다. 실제로 알고 있는 정보는 적어서, 예정처럼 혼자 작업을 했다면 꽤 긴 시간을 작업해야했을 것이다. VB.NET과 같이 쉬운 언어로 작업을 하면서도 의외로 많은 문제에 부딪쳤다.
개발언어 선택은 일단은 VB.NET으로 작업, 추후에 C++로 포팅하는 방법론은 성공적이었다.  Active Directory를 제대로 알지도 못하는 상황에서 만약 C++로 초기개발부터 시작을 했다면 포인터를 잘못 사용했거나, COM으로 작성된 라이브러리를 제대로 사용을 못했는지 등의 사소한 실수와, Active Directory를 제대로 몰라서 문제가 발생을 했는지를 제대로 판단하기 어려웠을 것이다. 작성한 코드의 길이가 길어질수록 문제점을 찾는 일은 더 어려워진다는 점도 무시할 수 없다. VB로는 약 300-400라인의 소스코드가 나왔는데 이를 C++로 작업했을 때는 어느정도의 양이 나올지 대충 생각을 해봐도 꽤나 아득하다. (.NET 기반의 언어들은 COM을 사용하는데 아주 편리해서 그것만으로도 코드의 길이 차이가 꽤 될듯 하다.) 작업후 실제로 포팅은 수행하지 않았는데, 작업결과가 특별한 문제점이 보이지 않았고, 고객에게 먼저 실행결과와 소스를 리뷰한 결과 소스가 그리 길지 않다는 점에서 유지보수에 호의를 보였다.(물론 고객을 잘 만난거 같기도 하다. 꽤 많은 시행착오가 있었는데 너그러이 그리고 잼있게 같이 작업을 할 수 있었으니 -ㅅ-)
가장 큰 성과는 짝프로그래밍의 생산성 및 성과를 확인할 수 있었던 것이다. [대안언어축제]에서 겪었던 경험이 실제 업무에서도 충분히 효과적임을 확인할 수 있었고, 이는 Crazia와의 협업에서도 잘 나타났다. 두 사람 모두 짝프로그래밍에 대해서 긍정적인 반응을 보였고 꽤나 잼있었다. 기존에도 Crazia와 몇몇 서버 코드를 작성시에 짝프로그래밍을 했었으나, 대부분의 작업은 1人이 작업하는 정보를 다른 1人이 작성한 서버 프로그램을 수정하는데 주로 사용되었다. 새로운 부분에 대해서도 어찌보면 더 폭발(!)적인 생산성을 보일 수 있다는 것은 고무적인 일이다.
다만 반성을 하자면 짝프로그래밍시에 너무 키보드를 독점하고 있지 않았나 하는 생각이 든다. 밸런스가 지나치게 무너졌던게 아닌가 (여전히 나는 아집과 고집이 쎄다.) 하는 생각이 드는데 그럼에도 불구하고 좋은 결과를 보인 것은 Crazia의 배려로 이루어졌던게 아닌가 하는 생각이 든다. - 이같은 점을 고치기 위해서 개인적인 노력 이외에도 회사에 짝프로그래밍용 타이머를 도입했다. -
Active Directory와 LDAP에 대해 습득한 지식이 기간이 짧아서 그리 체계적이지 않다. 전반적인 LDAP에 대한 개념도 그러하지만, Active Directory만 해도 .NET Framework에서 제공하는 API로는 Password의 값을 쓸 수만 있는데 이것을 읽어낼 방법 역시 추후에 비슷한 일을 맡게 되면 필요할지 모르는 일이다. (상식적으로는 왠지 가능할것 같지는 않기도 하다.) 상대적으로 거의 일어날리 없겠지만 M$솔루션의 사용자계정정보를 타기종 시스템으로 이전할 일이 왜 없겠는가? (실제로 IBM AS/400 관련 조사에서는 해당 솔루션을 판매하고 있었다.)

사족)
앞으로 개발을 하면서 겪었던 경험을 이 카테고리에 정리해 나갈 생각입니다. 가장 먼저 적는 글이라 근래에 했던 일중에 잼있었던 프로젝트를 다뤘습니다. 자주는 아니더라도 자신이 해왔던 일들에 대한 발자취를 남기는 공간으로 활용하려고 합니다.
그리고 이글에서는 회사 동료분들의 실명을 직접 쓰기는 어려우니 닉을 쓰기로 했습니다. KOEI는 아실테구 이글에서 같이 작업을 한 Crazia는 제가 다니는 회사 사장님이십니다. CEO이시기 이전에 풍부한 개발경험을 가진 아주 Smart 한 개발자이시기도 합니다. 실제 개발에서 시도 방법이라든가 문제를 바라보는 방법, 그리고 개발스킬(게으른 개발방법론도 포함. 나중에 일례를 소개하겠음) 많은 것의 배움의 대상이기도 하지요~


태그 : , , ,
트랙백1 | 댓글0
이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/474
Tracked from 해적의 쉼터 2007/01/17 15:11 x
제목 : Active Directory 에 사용자 정보 넣기
누리인포스 라는 회사에서 아는 사이니 도와달라고 하는 일을 억지로 맡아서 하게 됐습니다. 그래서 아는 사이가 더 무섭다는 말을 하는 겁니다. 좋게 좋게 대해주면 사람을 무시하게 되는건가요. 하지만 그건 있습니다. 너무 열받아 할 필요는 없다는거지요 , 그 사람은 저에게 빚을 지고 있는것이니까요 일 자체의 컨셉은 간단했습니다. 초기 목적은 AS400 의 사용자 정보를 가져와서 Active Directory 에 그 내용을 입력하는것이였습니다. 그게 AS..

[로그인][오픈아이디란?]
아이디 :
비밀번호 :
홈페이지 :
  비밀글로 등록
내용 :
 



[PREV] [1] [NEXT]
관리자  |   글쓰기
BLOG main image
소소한 일상.. 그안의 나..
전체 (11)
개발이야기 (7)
전산쟁이 맹달이 (2)
사랑하는사람들 (2)
Reading (0)
데스크탑 Ubuntu agile Feisty libpcap COBL call_graph 리눅스 Ruby 짝프로그래밍 삽질 tcpdump VB.NET 개발 AIX TCP 조카 나연이
COBOL call flow 그려보기 (8)
Ruby 그리고 AIX (4)
libpcap linux에서 timeout... (2)
사랑하는 조카 =)
[리뷰] Ubuntu Feisty - 충분... (6)
헙 마님 3개월만에 들어와봤...
2009 - KOEI
별걸 다 해 -_-
2009 - seha
냥냥 올만이야 3달만의 리플...
2008 - KOEI
광용싸마~ 간만이에용~ㅋㅋ...
2008 - nurinamu
로오오오옹 타이이임 노오오...
2008 - KOEI
Active Directory 에 사용자...
해적의 쉼터
Total : 23843
Today : 0
Yesterday : 18
태터툴즈 배너
rss
 
 
 
위치로그 : 태그 : 방명록 : 관리자
KOEI’s Blog is powered by Tattertools.com / Designed by plyfly.net