SAML Response 검증

NAVER WORKS는 SAML Request를 받으면 이를 검증한 후 로그인 페이지를 실행한다.
이때, SSO를 사용하는 도메인이면 고객사의 로그인 페이지로, 그렇지 않다면 NAVER WORKS의 로그인 페이지를 이용해 로그인을 한다.

로그인에 성공하면 SAML Response를 생성하여 고객사의 ACS URL로 전달한다.

Request URL {#verify-saml-request-url}

SAML Request에 명시한 ACS URL을 사용한다.
단, Developer Console에 등록한 ACS URL과 동일해야 한다.

HTTP Method {#verify-saml-request-parameter}

SAML Request에 명시한 Protocol Binding에 따라 GET 또는 POST를 사용한다.
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"일 경우 POST이고, 그 외는 GET을 사용한다.

Request {#verify-saml-request-parameter}

파라미터타입필수 여부설명
SAMLResponseStringYSAML 2.0 Response 명세에 따른 문자열
- Protocol Binding이 HTTP-POST인 경우: Base64로 인코딩
- 그 외의 경우: Deflate + Base64로 인코딩
RelayStateStringNSP 측에서 전달할 때만 Response에 전달

참고

  • SAML Response 안에는 Developer Console에 등록한 인증서로 전자 서명한 값이 포함되어 있으므로, 고객사는 반드시 전자 서명 값을 검증해야 한다.

SAML Response 명세 {#verify-saml-response-body}

<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"Destination="{NAVER WORKS에 등록한 ACS URL}" ID="{NAVER WORKS에서 발행하는 ID}" InResponseTo="{SAML Request에 포함된 ID}" IssueInstant="{SAML Response 생성 일시}"  Version="2.0">  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">  {Response Issuer}  </saml2:Issuer>  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">      "{디지털 서명}"  </Signature>  <saml2p:Status>    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>  </saml2p:Status>  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"  ID="{NAVER WORKS에서 발행하는 ID}"  IssueInstant="{SAML Response 생성 일시}"  Version="2.0">    <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">    {Response Issuer}    </saml2:Issuer>    <saml2:Subject>      <saml2:NameID Format="unspecified">      "{로그인한 사용자 NAVER WORKS ID}"      </saml2:NameID>      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">        <saml2:SubjectConfirmationData        InResponseTo="{SAML Request에 포함된 ID}"        NotOnOrAfter="{SAML Response 종료 일시}"        Recipient="{ACS URL}"/>      </saml2:SubjectConfirmation>    </saml2:Subject>    <saml2:Conditions NotBefore="{SAML Response 시작 일시}"    NotOnOrAfter="{SAML Response 종료 일시}">      <saml2:AudienceRestriction>        <saml2:Audience>{NAVER WORKS에 등록한 SP Issuer}        </saml2:Audience>      </saml2:AudienceRestriction>    </saml2:Conditions>    <saml2:AuthnStatement AuthnInstant="{SAML Response 생성 일시}"     SessionIndex="{NAVER WORKS에서 발행하는 ID}">      <saml2:AuthnContext>        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>      </saml2:AuthnContext>    </saml2:AuthnStatement>  </saml2:Assertion></saml2p:Response>

SAML Response의 각 항목은 다음과 같다.

항목타입필수 여부설명
Response DestinationStringYSAML Request에 포함된 ACS URL
Response IDStringYNAVER WORKS에서 발행하는 ID
Response InresponseToDate(UTC)YSAML Request에 포함된 ID
Response IssueInstantDate(UTC)YSAML Response 생성 일시
SignatureStringY디지털 서명
Assertion IDStringNNAVER WORKS에서 발행하는 ID
Assertion IssueInstantDate(UTC)NSAML Response 생성 일시
Subject NameIDStringY로그인한 사용자의 NAVER WORKS ID
SubjectConfirmationData InResponseToStringYSAML Request에 포함된 ID
SubjectConfirmationData NotOnOrAfterDate(UTC)YSAML Response 종료 일시
SubjectConfirmationData RecipientStringYACS URL
Conditions NotBeforeDate(UTC)YSAML Response 시작 일시
Conditions NotOnOrAfterDate(UTC)YSAML Response 종료 일시
AudienceStringYSAML Request에 포함된 Issuer
AuthnStatement AuthnInstantDate(UTC)YSAML Response 생성 일시
AuthnStatement SessionIndexStringYNAVER WORKS에서 발행하는 ID

SAML Response Example {#verify-saml-response-body-example}

<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://www.example.com/vendor.com/acs" ID="iikplioanoofjomkgckmmamjfipjnbcmjhindmgd" InResponseTo="akidlcfmckodoaojopljbhcaieejopdiebeelgke" IssueInstant="2018-02-27T05:42:27.614Z" Version="2.0">  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://auth.worksmobile.com/saml2/example.com</saml2:Issuer>  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">    ...  </Signature>  <saml2p:Status>    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>  </saml2p:Status>  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="mojkjoofkhhfdgcajjommcnjdmclnbbibamkaojh" IssueInstant="2018-02-27T05:42:27.678Z" Version="2.0">    <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://auth.worksmobile.com/saml2/example.com</saml2:Issuer>    <saml2:Subject>      <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">dev@vendor.com</saml2:NameID>      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">        <saml2:SubjectConfirmationData InResponseTo="akidlcfmckodoaojopljbhcaieejopdiebeelgke" NotOnOrAfter="2018-02-27T05:47:27.678Z" Recipient="https://www.example.com/vendor.com/acs"/>      </saml2:SubjectConfirmation>    </saml2:Subject>    <saml2:Conditions NotBefore="2018-02-27T05:42:27.678Z" NotOnOrAfter="2018-02-27T05:47:27.678Z">      <saml2:AudienceRestriction>        <saml2:Audience>sp issuer</saml2:Audience>      </saml2:AudienceRestriction>    </saml2:Conditions>    <saml2:AuthnStatement AuthnInstant="2018-02-27T05:42:27.678Z" SessionIndex="bjbgljemhimbdimmpdjcbelfeakfhdpcdmebjcna">      <saml2:AuthnContext>        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>      </saml2:AuthnContext>    </saml2:AuthnStatement>  </saml2:Assertion></saml2p:Response>