.NET 클라이언트 라이브러리에서 AuthSub 사용

Jeff Fisher, Google 데이터 API팀
2007년 8월

소개: AuthSub가 중요한 이유

Google Data API(줄여서 'GData')는 개발자가 Google 서비스와 상호작용하는 애플리케이션을 개발자가 빌드하도록 지원하는 방식입니다. 더 구체적으로 설명하면 애플리케이션에서 사용할 비공개 사용자 데이터에 액세스할 수 있습니다. API를 사용하면 해당 데이터를 동기화, 가져오기, 내보내기 또는 관리할 애플리케이션을 작성할 수 있습니다. API는 이러한 강력한 기능을 제공하지만, 기능을 책임감 있게 사용해야 합니다. 사용자 데이터는 비공개 정보이므로 당연히 안전한 방식으로 액세스해야 합니다. 여기서 중요한 부분은 Google 서버에 안전한 방식으로 인증하는 것입니다.

Google 웹 서비스에 저장된 데이터에 연결하고 싶은 훌륭한 새로운 웹 애플리케이션이 있다고 가정해 보겠습니다. 이제 이 비공개 데이터에 액세스하기 위해 인증하려고 합니다. ClientLogin과 같은 간단한 함수를 사용하면 안 되나요? 그렇게 할 수는 있지만 훨씬 더 더 많은데이터, 즉 사용자의 로그인 인증 정보를 처리합니다. ClientLogin을 사용하려면 애플리케이션에서 사용자의 Google 사용자 이름 및 비밀번호를 요청해야 합니다. 사용자의 개인 컴퓨터에서 실행되는 데스크톱 애플리케이션에는 적합하지만 웹 기반 애플리케이션에는 적합하지 않습니다. 사용자 인증 정보를 자체 서버에서 처리해야 하는 것 외에 더 신중한 사용자도 자신의 정보가 저장될까 봐 걱정할 것입니다. 또 다른 일반적인 문제는 사용자가 특정 서비스 (예: Google Calendar의 일정)에만 액세스 권한을 부여하되 다른 서비스 (예: Google 문서)에는 부여하지 않으려는 경우입니다. AuthSub는 사용자가 Google 서버를 통해 인증하도록 하여 이 두 가지 문제를 모두 해결하고 프로그램에서 필요한 액세스만 요청하도록 허용합니다.

AuthSub 이론에 대해 충분히 읽었으므로 이제 코딩을 살펴보겠습니다. 이 글에서는 작업을 단순하게 유지하고 단일 ASP 페이지에서 모든 작업을 수행하기로 했지만 여기서 설명하는 기법을 내 애플리케이션에 쉽게 통합할 수 있을 것입니다.

인증 처리

그렇다면 웹 애플리케이션에서 실제로 AuthSub를 사용하려면 무엇이 필요한가요? 먼저 GData 클라이언트 라이브러리에서 몇 가지 표준 가져오기가 있습니다.

<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="System.Net" %>

이제 가장 먼저 해야 할 일은 사용자를 특별히 제작된 URL로 보내는 것입니다. 이렇게 하면 Google 서버에서 인증을 처리한 다음 사용자를 다시 내 웹사이트로 리디렉션합니다. 다행히 이 URL을 생성할 수 있는 방법이 있으므로 직접 생성하지 않아도 됩니다. 예를 살펴보겠습니다.

authSubUrl = AuthSubUtil.getRequestUrl(target, scope, secure, session);
  • target: 웹 애플리케이션의 URL이 포함된 문자열입니다. 인증 후 사용자가 리디렉션되는 페이지입니다.
  • 범위 이 문자열은 사용 중인 API에 따라 결정됩니다. GData API의 피드 중 하나에 해당합니다. 예를 들어 사용자의 모든 캘린더 정보가 포함된 피드는 'http://www.google.com/calendar/feeds/default/private/full'입니다.
  • secure: Google에 등록했으며 서버에 암호화 방식으로 서버에 서명함을 서버에 알리는 부울입니다. 이 인수는 특히 테스트 환경에서 작업할 때 일반적으로 false입니다.
  • session: '일회용 토큰'이 아닌 '세션 토큰'을 원함을 나타내는 또 다른 불리언입니다. 곧 이 인수의 역할이 더 명확해집니다.

생성된 URL을 클릭하면 Google 계정에 로그인할 수 있는 Google 계정 페이지로 이동합니다. 일회용 토큰이 포함된 쿼리 매개변수 'token'을 사용하여 지정된 'target' 웹페이지로 리디렉션됩니다. 일반적으로 이 토큰은 정확히 한 번만 사용할 수 있습니다. 즉, 특정 피드에서 하나의 작업을 실행하는 데 사용할 수 있습니다. 그러나 'session' 매개변수를 true로 지정한 경우 '세션 토큰'으로 교환하여 사용자가 세션을 종료할 때까지 재사용할 수 있습니다. 방법은 다음과 같습니다.

String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();

여기에서 쿼리 매개변수에서 토큰을 추출하고 '세션 토큰'으로 교환합니다. 그런 다음 나중에 사용할 수 있도록 .NET의 자동 Session 배열에 저장하도록 선택할 수 있습니다. 토큰을 토큰 내에 저장하도록 선택할 수도 있습니다. 다음 단계는 이 토큰을 사용하여 인증된 요청을 하는 것입니다.

GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "My-Cool-Application");
authFactory.Token = (String) Session["token"];
CalendarService service = new CalendarService(authFactory.ApplicationName);
service.RequestFactory = authFactory;

여기에서는 인증을 위해 AuthSub를 사용하여 Google Calendar API와 상호작용하도록 CalendarService 객체를 설정합니다. GAuthSubRequestFactory의 생성자에 사용된 'cl'은 Calendar의 서비스 이름입니다. 다른 서비스 이름은 Google Data API FAQ를 참고하세요.

보안 (등록된) AuthSub

웹 애플리케이션을 등록하면 AuthSub를 사용하는 동안 추가 보안 수준을 사용 설정할 수 있습니다. 이렇게 하면 코드로 생성된 모든 요청에 디지털 방식으로 서명할 수 있으므로, 다른 사람이 비공개 키를 보유하지 않는 한 나에게 발급된 AuthSub 토큰을 사용할 수 없게 됩니다. 첫 번째 단계는 AuthSubUtil.getRequestUrl를 호출할 때 'secure' 인수를 true로 설정하여 올바른 AuthSub 링크를 생성하는지 확인하는 것입니다. 그 외에 다음과 같은 두 가지 코드 변경이 필요합니다.

String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, rsaKey).ToString();

...

authFactory.PrivateKey = rsaKey;

먼저 null 대신 'rsaKey' 변수를 exchangeForSessionToken 메서드에 전달합니다. 이 변수는 서비스에 대한 연결을 설정할 때 GAuthSubRequestFactory의 속성을 설정하는 데도 사용됩니다. 'rsaKey' 변수는 Google에 등록한 x509 인증서의 비공개 키 구성요소에 해당하는 RSACryptoServiceProvider입니다.

.NET Framework가 PEM 형식으로 저장된 키 또는 인증서를 이해하지 못하기 때문에 RSA 비공개 키 및 자체 서명 인증서를 생성하는 것은 다소 혼란스러울 수 있습니다. 다음 명령어는 OpenSSL 도구 모음을 사용하여 비공개 키 및 공개 인증서를 생성하는 방법을 보여줍니다.

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj \
  '/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout \
  test_key.pem -out test_cert.pem

openssl pkcs12 -export -in test_cert.pem -inkey test_key.pem \
  -out test_cert.pfx -name "Testing Certificate"

첫 번째 단계에서는 각각 'test_key.pem' 및 'test_cert.pem'이라는 PEM 형식으로 비공개 키와 공개 X509 인증서를 생성합니다. 인증서는 미국 캘리포니아주 마운틴뷰에 소재한 'www.example.com'에 등록되도록 설정되어 있습니다. 여기에서 회사에 적합한 값을 입력하세요. 'test_cert.pem' 파일에는 AuthSub 등록 페이지에 제출해야 하는 정보가 포함되어 있습니다.

두 번째 단계에서는 비공개 키 및 인증서에서 PFX 파일을 생성합니다. 이 파일을 .NET 클라이언트 라이브러리로 가져와 GData API에 대한 요청에 디지털 서명할 수 있습니다. 다음 코드는 PFX 파일의 비공개 키를 웹 애플리케이션으로 가져오는 방법을 보여줍니다.

protected AsymmetricAlgorithm getRsaKey()
{

  X509Certificate2 cert = new X509Certificate2("C:/MyAspSite/test_cert.pfx","");
  RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;

  return privateKey;
}

이 스니펫에 의해 정의된 getRsaKey() 함수는 API 인증에 사용할 때 위에 표시된 'rsaKey' 변수 대신 사용할 수 있습니다. 당연히 파일 경로는 생성한 PFX 파일의 적절한 위치로 대체해야 합니다.

전체 코드 등록정보

이전 섹션에서 설명한 방법을 사용하는 가장 쉬운 방법은 라이브 예시를 사용하는 것입니다. 다음 샘플 코드는 AuthSub를 사용하여 사용자를 인증한 다음 Google Calendar의 일정을 출력하는 간단한 ASP 페이지입니다.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="Google.GData.Calendar" %>
<%@ Import Namespace="System.Net" %>

<script runat="server">
    void PrintCalendar() {

        GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "TesterApp");
        authFactory.Token = (String) Session["token"];
        CalendarService service = new CalendarService(authFactory.ApplicationName);
        service.RequestFactory = authFactory;

        EventQuery query = new EventQuery();

        query.Uri = new Uri("http://www.google.com/calendar/feeds/default/private/full");

        try
        {
            EventFeed calFeed = service.Query(query);
            foreach (Google.GData.Calendar.EventEntry entry in calFeed.Entries)
            {
                Response.Write("Event: " + entry.Title.Text + "<br/>");
            }
        }
        catch (GDataRequestException gdre)
        {
            HttpWebResponse response = (HttpWebResponse)gdre.Response;
            
            //bad auth token, clear session and refresh the page
            if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                Session.Clear();
                Response.Redirect(Request.Url.AbsolutePath, true);
            }
            else
            {
                Response.Write("Error processing request: " + gdre.ToString());
            }
        }
    }

</script>


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Test Site</title>
</head>
<body>

    <form id="form1" runat="server">
    <h1>AuthSub Sample Page</h1>
    <div>
    <%
        GotoAuthSubLink.Visible = false;
        
        if (Session["token"] != null)
        {
            PrintCalendar();
        }
        else if (Request.QueryString["token"] != null)
        {
            String token = Request.QueryString["token"];
            Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
            Response.Redirect(Request.Url.AbsolutePath, true);
        }
        else //no auth data, print link
        {
            GotoAuthSubLink.Text = "Login to your Google Account";
            GotoAuthSubLink.Visible = true;
            GotoAuthSubLink.NavigateUrl = AuthSubUtil.getRequestUrl(Request.Url.ToString(),
                "http://www.google.com/calendar/feeds/",false,true);
        }
        
     %>
    <asp:HyperLink ID="GotoAuthSubLink" runat="server"/>

    </div>
    </form>
</body>
</html>

마무리

AuthSub를 사용하면 웹 애플리케이션이 사용자의 Google 계정에 저장된 데이터에 안전하고 제어된 방식으로 액세스할 수 있습니다. .NET 클라이언트 라이브러리를 사용하면 ASP 기반 웹사이트를 Google 서비스와 쉽게 통합할 수 있습니다. 이 도움말은 시작하는 데 도움이 되지만 참조하면 좋은 추가 리소스가 있습니다.