oauth 메일링 리스트에 James Manger의 현재 oauth스팩에 대한 한계점과 그에대한 proposal을 하는 스레드 6월 24일자로 있어서 간단하게 정리해 봅니다. oauth 차후 버전에 꼭 있었으면 하는 부분들이 제안에 있어서 반갑기까지 하네요.ㅋ 직역하여서 어색한 부분 있더라도 양해 바랍니다. 문맥상 이상한 부분 있는데 댓글로 검수해주시면 정말 감사히 고치겠습니다.^^
그러고 보니 바로 오늘(08/6/26)이 OAuth summit이 열리는 날이네요~ 좋은 결과 있기를~.


Disentangling delegation and authentication

OAuth가 인증 메커니즘을 위임하는데 있어서 의존도를 더 적게 명시할 수 있다면, 더 이해하기에 좋고, 구현하기 좋으며, 확장하기도쉬워질 것이다. 곧 있을 OAuth summit에서 OAuth 1.1혹은 2.0에서 이슈가 될 것을 기대해본다.

OAtuh 1.0은 4개의 튜플로 이루어진 핵심 데이터 모델을 가진다 :
token, token secret, consumer key, consumer secret
그리고 3개의 인증 알고리즘을 지원한다:
PLAINTEXT, HMAC-SHA1, and RSA-SHA1

이러한 구성 요소들이 다음과 같이 적시적소에 쓰인다면 전혀 문제 될 것이 없다 :    

Request(with 4-tuples) --> [algorithm] --> authentic request
그러나, 여러가지 예외사항들이 발생할 수 있다.

  1. request token을 요청했는데 아무런 token 혹은 token secret이 없을 때
  2. 사용자를 서비스로 리다이렉트 시킬 때, 사이닝(signed)이 되지 않은 요청일 경우
  3. PLAINTEXT 알고리즘은 항상 token과 token secret을 함께 보내는데, 한개의 item만 갈 수가 있다(즉, token secret은 없이 token만)
  4. RSA-SHA1 알고리즘은 token secret을 무시한다.
  5. RSA-SHA1 알고리즘은 별도의 consumer private RSA key가 있어서 consumer secret 이 필요가 없다.
  6. desktop app 나 javascript widget은 많은 사용자의 컴퓨터에서 돌아감에 따라 주어진 consumer secret을 보호하기 어렵기 때문에 그것을 사용할 수 없다.
  7. 등록을 취소한 app는  consumer key 혹은 consumer secret을 가지지 않는다.
  8. app와 service간에 어떤("2-way") 트랜잭션은 사용자에게 속한(behalf)것이 아니므로 token이나 token secret이 없다.

위에 제시한 각각의 예외사항은 충분히 일어날 수 있다. 그러나 이렇게 많은 예외를 위해 필요사항을 모델에 제안하는 것은 틀리다. 우리는 이러한 문제를 현명하게 나누지 않았다. 

대안은 어떤 standalone 인증 알고리즘을 정의하는 것이다.

OAuth-RSA
서버는 401 응답에 다음과 같은 헤더정보를 넣은 OAuth-RSA를 지원하도록 지시할 수 있다:
 

WWW-Authenticate: OAuth-RSA realm=...
    how=uri,header,body what=header,body

클라이언트는 header 그리고/혹은 body의 RSA private key로 사이닝을 할 것이고, Authorization header나 query params혹은 body에 
signature등을 넣어야할것이다.

OAuth-PLAIN
서버는 401 응답에 다음과 같은 헤더정보를 넣은 OAuth-PLAIN을 지원하도록 지시할 수 있다:

  WWW-Authenticate: OAuth-PLAIN realm=...
    how=uri,header,body

클라이언트는 Authorization header 혹은 query params 혹은 body에
oauth_secret파라미터를 포함시켜야 할 것이다.

OAuth-HMAC
서버는 401 응답에 다음과 같은 헤더정보를 넣은 OAuth-HMAC를 지원하도록 지시할 수 있다:

  WWW-Authenticate: OAuth-HMAC realm=...
    how=uri,header,body what=header,body

클라이언트는 headre 그리고/혹은 body에 message authentication code(MAC)을 계산하고,
Authorization header 혹은 query params 혹은 body에 MAC등을 넣어야 할 것이다.

["what" indicates what parts of the request to sign;
"how" indicates how to incorporate the result into the request;
both could list all supported options]

이렇게 정의된 알고리즘은 특정 위임에 대한 것이 아니다. 이는 어떤 HTTP 요청에 대해서도 사용될 수 있다.

OAuth는 다른 알고리즘을 효율적으로 정의한다: 하위 요청을 통해 MAC을 계사하는데 사용되는 한개의 응답에 secret을 제공하는 것. 이는 특이한 메커니즘이다. 이처럼 동작하는 어떤 인증 스킴도 알지 못하지만, 이는 몇몇 보안상의 잇점을 제공한다. 이것에 대해서 생각하는 가장 좋은 방법을 찾았는데, 그것은 'crypto cookie'이다. 이는 하위 요청에 사용되어지는 일부(blob) 서버 응답의 표준 쿠키와 유사하다. 그러나 blob을 포함하는 것 대신에 그것을 직접적으로 노출하지 않고 당신이 blob을 알고 있음을 증명하는데 사용되는 MAC을 포함할 수 있다. 이러한 방식으로 우리는 4번째 인증 메커니즘을 정의할 수 있다.

OAuth-Crypto-Cookie
서버는 401 응답에 다음과 같은 헤더정보를 넣은 OAuth-Crypto-Cookie지원하도록 지시할 수 있다:
  WWW-Authenticate: OAuth-Crypto-Cookie realm=... secret=...
    how=uri,header,body what=header,body

클라이언트는 MAC key로 secret을 사용하고 OAuth-HMAC당 인증 요청을 해야할 것이다.

마지막으로 OAuth 전체적인 관점에서의 위임(delegation)이 있다.
나는 위임(delegation)에 대한 HTTP 인증 메커니즘을 분리하여 접근하는 것을 좋아한다.

OAuth
서버는 401 응답에 다음과 같은 헤더정보를 넣은 OAuth지원하도록 지시할 수 있다:

  WWW-Authenticate: OAuth realm=... authz=... access=...
    how=uri,header,body

클라이언트는 authz URI로 사용자를 리다이렉트 시켜야 할 것이다(선택적으로 callback URI를 포함).  클라이언트는 Authorization 헤더, 혹은 query params혹은 body에 oauth_token을 포함시켜야할 것이다.

OAuth는 OAuth-PLAIN, OAuth-RSA, OAuth-HMAC, OAuth-Crypto-Cookie, 혹은 어떤 다른 인증 메커니즘(HTTPS와 함께 클라이언트 확인(certs); app에 대한 OpenID ...)과 묶여질 수 있다. OAuth는 oauth_token을 지원한다: 위임을 구별하기 위하 서버로부터 사용되는 blob. 그것은 요청의 여타의 요청에 사이닝 될 수 있다.

만약 token이 자동으로  일정기간마다 갱신될 필요가 있다면, "WWW-Authenticate: OAuth"헤더에 "token=..."어트리뷰트를 추가할 수 있다. 만약 "token"이 현재형이고, "authz"는 그렇지 않다면, 단지 존재하는 모든 oauth_token을 새로운 값으로 교체하면 된다. 만약 "authz"가 현재형이면, 사용자는 리다이렉트되어야만 할 것이다.

컨텐트 서버로부터 보안서버가 분리된 프로바이더는 위임(delegation)혹은 갱신이 요구될때면 언제든지 컨텐스 사이트에서 보안 서버로의 요청을 리타이렉트 시킬 수 있다. 보안 서버는 어떤 OAuth[-*] 메커니즘을 사요앟ㄹ 수 있고, 따라서 컨텐트 사이트로 돌려서 요청을 리다이렉트 한다.

어떤 자세한 사항들이 겉보기에 그럴듯 하더라도, 어떤 인증을 풀어내는 컨셉과 위임(delegation)이 명료하기를 희망한다.

- James Manger

Posted by
OAuth그룹에서의 최근 근황을 적어봅니다.

이슈 1.
Yahoo가 주최하는 OAuth Summit 2008이 6월 26일 Santa Clara, CA에서 열릴 예정이라고 합니다.

이번 행사에서는 OAuth 프로토토콜, 확장성, OAuth 구현을 했던 경험 공유, 그리고 개발자들 간의 교류를 목적으로 합니다. 적어도 OAuth 스팩에 대한 이해를 가지고 참가해야 한다고 합니다.^^

이슈 2.
OAuth Core 1.0 Final이 2007년 12월 4일에 공표된 이후로, 커뮤니티에는 많은 피드백과 구현과정에서 추가적으로 필요한 제안들이 많이 올라왔었습니다. 그 이유인즉, 실제 OAuth Core 1.0에서 제시하는 바로는 실제 서비스 프로바이더와 컨수머간에 생길수 있는 여러가지고 요구사항을 충분히 수렴하지는 못했던 것이라고 생각합니다. 실제로 OAuth 컨수머와 프로바이더를 구현해보면서 앞으로 OAuth Core의 확장이 필요하다고 생각했었는데, 최근 OAuth그룹에서  Eran Hammer - Lahav가 제안한 OAuth Core 1.1 을 한번 정리해볼까 합니다.

- '리소스'와 '접근 요청', 그리고 '접근'이 가장 일반적인 질문이라고 할 수 있다. Core 1.0에는 각각의 프로바이더들이 개발해나가고자 하는 것을 배제하고 명세되어 있다.
- 명세는 다른 언어로 번역되야 하고, 더 많은 예제가 제공되어야 하며, Appendix A에 있는 전체 예제를 문서의 제일 위로 위치시켜서 가독성을 향상시킬 수 있겠다. 일반적으로 튜토리얼에서 시작하여 레퍼런스로 옮겨가기 때문.
- Core 1.0은 크리티컬한 상호운영에 대한 확실한 에러처리에 대해 부족하다.
- 확장성과 보안 부분에서 대규모 프로바이더에게 더 좋은 지원을 하기 위하여 명세를 수정해야 한다.

추가적으로, 다음과 같은 기능(feature)들이 요구되었다.
- HTTP Body signature : 페이로드(payload)데이터를 sign하는 방법 제공
- 언어 지원 : 메인 스팩에 extension을 포함.
- 2개의 플로우 : 어떻게 2개의 시나리오가 동일한 시그네이쳐 메소드를 사용하여 동작해야만 하는지에 대해 Core에 명확한 정의를 추가.(?)

다른 작은 제안들로는,
- RSA와, token secret을 제외하는 두가지 메소드들간의 보안상의 차이에 대해서 명확하게 해야함
- consumer 에 명시되어야 하는 nonce와 timestamp언어뿐 아니라 token에 명시되어야 하는 nonce와 timestamp언어 대해서도 명확히 해야 함.

Core, Extensions  어디에 포함시켜야 하는가?,
Core 1.0을 개발하면서 범위에 대해서, 그리고 그것이 core 프로토콜에 포함되어야 하는 것인지, extension에 속해야 하는 것인지에 대하여 긴 토론을 하였다. 위에 있는 모든 것이 core 명세에 포함되어야 하는 것은 아니지만, 우리가 작업한 것들이 가능한한 문서에 포함시켜야 하는 많은 이유가 있다. 현실적으로, 더 중요한 사항은 이해를 시켜주고 지원을 해주는 것이다.

Core 1.1의 범위 제안
- 에러 리포팅 : error code(URI 형식)와 사람이 읽을 수 있는 텍스트, 이 두가지 파라미터를 추가해야 한다. 일반적인 프로토콜 에러에 대한 코드의 집합을 정의해야 한다. 확장하기 쉽도록 스트링이나 숫자를 쓰는것 보다는 에러코드를 위하여 URI를 사용하는 것이 좋겠다.
- 2개의 플로우 : consumer key와 secret을 사용할때만, token과 token secret을 비워두는 경우, OAuth signature string을 어떻게 명시해야 하는지에 대한 정의
- HTTP Body signature : body의 시그내처를 지원할 새로운 파라미터 추가.(non-multi-part-bodies에 관점에 제한하여). 파라미터는 일반적인 플로우를 사용하여 인증을 받아냄.
- 언어 지원 : 스팩에 언어 제안 포함 
- RSA 보안과 nonce limitation에 대한 언어 수정
- 위에서 제안한 것을 기반으로 한 토큰 어트리뷰트에 대한 뼈대를 추가. 기본적으로 키/밸류 한쌍의 파라미터. 서비스프로바이더가 명세할 수 있는 것과 최소한의 키들의 집합 정의

references
- http://groups.google.com/group/oauth/t/808e4a98193de671?hl=en
- http://groups.google.com/group/oauth/t/b4d71abb0ac81e60?hl=en

Posted by
지난 OAuth 포스팅에서 공유하였던 OAuth 컨수머 루비 예제 코드는 루비OAuth 라이브러리 0.0.1을 사용했기 때무에 문제도 많아고 코드도 지저분 했었습니다.

  이 컨수머를 더미로 사용하면서 문제가 너무 많은 듯 한 나머지 현재 OAuth 루비 라이브러리 최신버전인 0.2.2를 사용한 컨수머 애플리케이션코드를 공유합니다.

기본적으로 인증 센터는 APICenter로 되어 있으며 openid(MyID)기반의 메시징 서비스인 Whisper의 OpenAPI를 사용하는 예제입니다. (Whisper에 가입이 되어 있다는 전제 하에 동작이 되도록 하였습니다.)

조금이라도 도웁이 되었으면 합니다.





참고 URL
- http://stakeventures.com/articles/2008/02/23/developing-oauth-clients-in-ruby
- http://oauth.rubyforge.org/

Posted by
3월 중으로 오픈마루 서비스의 API 인증방식이 OAuth1.0을/도 지원합니다

안녕하세요. 오픈마루 오픈플랫폼팀의 정상일(humbroll)입니다.

현재 웹 서비스들의 사용자 데이터 흐름이 서비스중심에서 사용자중심으로 움직이려는 모습을 보이고 있으며, 이는 매우 고무적인 현상이라고 생각합니다.

이를 위해서는 여러 서비스들에 흩어져 있는 사용자의 중요한 데이터들을 주고 받을 수 있는 그 무언가가 필요합니다. 현재 그 것을 위해 각 서비스 벤더들은 나름의 인증방식을 제공하고 있지만, 각 서비스마다 정의하는 바가 조금씩 다르고, 이에 따라 개발이 어려운 것이 현실입니다. '표준'의 부재가 가장 큰 문제이죠. 이를 해결하기 위하여 서비스와 서비스간의 사용자의 데이터 통신을 위한 인증의 표준화를 목적으로 OAuth(Open protocol Authorization)가 제기되었습니다.

차후 OAuth의 공식 한국어 페이지를 운영할 계획입니다만,

(현재로서 OAuth를 이해하기 위해서는 OAuth공식페이지김승현님의 OAuth에 대한 블로그 포스팅 을 참고하시면 되겠습니다.)

이에, 3월 중으로


오픈마루 서비스의 API 인증방식이 OAuth1.0을/도 지원할 예정입니다.

앞으로 OpenAPI를 제공하는 많은 서비스들이 이 OAuth를 적용하여 진정한 의미의 '사용자 중심의 웹'이 실혔되었으면 하는 바람입니다.

OAuth의 공식 홈페이지에 가보시면 각 언어들에 대한 라이브러리를 제공하며, 프로바이더와 컨수머 샘플코드도 어렵지 않게 찾아볼 수 있습니다. Ruby의 경우 프로바이더와 컨수머 구현을 위해서 oauth-plugin이나 oauth4r 이 제공되고 있지만 실제 세팅을 좀 더 해야하기때문에, oauth4r 에 있는 소스코드를 적용하여 '돌아가는' 샘플 코드를 공유합니다.


프로바이더 소스코드 : oauth_provider.tar

컨수머 소스코드 : oauth_consumer.tar


rails버전이 2.0 이하일 경우는

  • gem update --system

로 rails환경 전체를 업데이트 하거나 이것이 여유치 않으실 경우는

하셔서 rails를 임베드하시기 바랍니다.

필요한 라이브러리를 설치합니다. oauth, ruby-hmac

  • gem install oauth
  • gem install ruby-hmac

OAuth 샘플코드 구동을 하기 위한 설명을 간단히 하겠습니다.

각 프로젝트에서 config/database.yml 에서 디비 설정을 하신 후

  • rake db:create && rake db:migrate

를 합니다. 한번 실행시켜 봅시다.

컨수머는 5000포트를, 프로바이더는 5001포트를 사용합니다.(코드를 직접 고치셔서 다른 포트로 사용해도 무방합니다.)

컨수머 프로젝트에서는

  • ruby script/server -p 5000

프로바이터 프로젝트에서는

  • ruby script/server -p 5001

합니다.


우선 컨수머사이트(5000포트를 쓰는)를 프로바이더사이트(5001포트를 쓰는)에 등록해야 합니다.

http://localhost:5001/ => http://localhost:5001/get_contacts/new 에 있는 텍스트필드에 http://localhost:5000/use_get_contacts/oauth/callback 입력(컨수머의 config/use_get_contacts.oauth.yml에서 수정 가능) 한 후 Registaer버튼 클릭=> 화면의  Consumer Key값과 Consumer Secret값을 컨수머프로젝트의 config/use_get_contacts.oauth.yml의  consumer_key,consumer_secret값으로 삽입 =>컨수머사이트(5000포트) 재시작 => http://localhost:5000/users 에서   New user 링크를 통해 사용자 등록=>Establish OAuth with provider @ http://localhost:5001/get_contacts/authorize  링크를 통해서http://localhost:5000/use_get_contacts/new 로 이동하여 Create 클릭

이 때부터 컨수머와 프로바이더 사이의 인증이 시작됩니다.

5001번사이트에 로그인이 안되어 있을 경우는 로그인을 하라고 하고, 로그인을 하면 컨수머사이트에서 프로바이더사이트에 있는 사용자의 데이터 접근을 허가할 것인지에 대해서 물어봅니다.


Yes클릭!


다시 컨수머사이트로 돌아올 것입니다. 이로서 모든 인증 과정이 끝나고 프로바이더의 이른바 Protected Resource에 접근할 수 있는 Access Token과 Access Secret을 받옵니다.

다음과 같이 access token을 받아왔습니다. (access secret도 역시 받은 상태입니다)


Successful, access_key(13831917959380963787) received


이상입니다.


back-end에서 이루어지는 인증절차는 OAuth1.0 Spec에 잘 나와 있지만 다음 그림을 보시면 더 쉽게 이해하실 수 있습니다.



샘플에 문제가 있으면 댓글 남겨주시기 바랍니다.

많은 서비스들이 사이좋게 서로의 프로바이더, 컨수머가 되어 더 낳은 '웹'이 되길 희망합니다. ^^/

이 글은 스프링노트에서 작성되었습니다.

p.s : me2day에서도 곧 oauth를 지원해 주시리라 믿습니다! -0-/
Posted by