상위 질문
타임라인
채팅
관점
SAML 2.0
위키백과, 무료 백과사전
Remove ads
SAML 2.0((Security Assertion Markup Language 2.0)은 SAML(Security Assertion Markup Language) 표준의 한 버전으로, 보안 도메인 간에 인증 및 권한 부여 식별자를 교환하는 데 사용된다. SAML 2.0은 XML 기반 통신 프로토콜로, ID 공급자라고 하는 SAML 기관과 서비스 공급자라고 하는 SAML 소비자가 교장(일반적으로 최종 사용자)에 대한 정보를 전달하는 보안 토큰을 사용한다. SAML 2.0은 웹 기반의 도메인 간 단일 로그인 (SSO)을 가능하게 하여 사용자에게 여러 인증 토큰을 분배하는 관리 오버헤드를 줄이는 데 도움이 된다. SAML 2.0은 2005년 3월 OASIS 표준으로 비준되었으며, SAML 1.1을 대체했다. SAML 2.0의 중요한 측면은 공식 문서인 SAMLCore,[1] SAMLBind,[2] SAMLProf,[3] 및 SAMLMeta[4]에 자세히 설명되어 있다.
24개 이상의 회사와 기관에서 약 30명의 개인이 SAML 2.0 생성에 참여했다. 특히 리버티 얼라이언스는 ID 연합 프레임워크(ID-FF) 사양을 OASIS에 기증했는데, 이 사양은 SAML 2.0 사양의 기반이 되었다. 따라서 SAML 2.0은 SAML 1.1, 리버티 ID-FF 1.2 보관됨 2021-02-24 - 웨이백 머신, 그리고 시볼레스 1.3의 융합을 나타낸다.
Remove ads
SAML 2.0 어설션
요약
관점
어설션은 SAML 기관이 만든 0개 이상의 문장을 제공하는 정보 패키지다. SAML 어설션은 일반적으로 <Subject> 요소로 표현되는 주체에 대해 만들어진다. SAML 2.0 사양은 SAML 기관이 만들 수 있는 세 가지 유형의 어설션 문장을 정의한다. 모든 SAML 정의 문장은 주체와 관련이 있다. 세 가지 유형의 어설션 문장은 다음과 같이 정의된다.
- 인증 문: 어설션 주체가 특정 시점에 특정 수단으로 인증되었다.
- 속성 문: 어설션 주체는 제공된 속성과 연결된다.
- 권한 부여 결정 문: 어설션 주체가 지정된 리소스에 액세스하는 것을 허용하거나 거부하는 요청이 승인되거나 거부되었다.
SAML 어설션의 중요한 유형은 웹 브라우저 SSO를 용이하게 하는 소위 "전달자(bearer)" 어설션이다. 다음은 ID 공급자(https://idp.example.org/SAML2)가 서비스 공급자(https://sp.example.com/SAML2)에게 발급한 단기 전달자 어설션의 예시다. 이 어설션에는 서비스 공급자가 액세스 제어 결정을 내리는 데 사용하는 것으로 추정되는 인증 어설션 <saml:AuthnStatement>과 속성 어설션 <saml:AttributeStatement>이 모두 포함되어 있다. 접두사 saml:은 SAML V2.0 어설션 네임스페이스를 나타낸다.
SAML 예시
<saml:Assertion
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
ID="_d71a3a8e9fcc45c9e9d248ef7049393fc8f04e5f75"
Version="2.0"
IssueInstant="2004-12-05T09:22:05Z">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<saml:Subject>
<saml:NameID
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
3f7b3dcf-1674-4ecd-92c8-1544f346baf8
</saml:NameID>
<saml:SubjectConfirmation
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
InResponseTo="aaf23196-1773-2113-474a-fe114412ab72"
Recipient="https://sp.example.com/SAML2/SSO/POST"
NotOnOrAfter="2004-12-05T09:27:05Z"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions
NotBefore="2004-12-05T09:17:05Z"
NotOnOrAfter="2004-12-05T09:27:05Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.com/SAML2</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement
AuthnInstant="2004-12-05T09:22:00Z"
SessionIndex="b07b804c-7c29-ea16-7300-4f3d6f7928ac">
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
x500:Encoding="LDAP"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1"
FriendlyName="eduPersonAffiliation">
<saml:AttributeValue
xsi:type="xs:string">member</saml:AttributeValue>
<saml:AttributeValue
xsi:type="xs:string">staff</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
위 예시에서 <saml:Assertion> 요소에는 다음 자식 요소가 포함되어 있다.
- ID 공급자의 고유 식별자를 포함하는
<saml:Issuer>요소 <saml:Assertion>요소에 대한 무결성을 보존하는 디지털 서명(표시되지 않음)을 포함하는<ds:Signature>요소- 인증된 주체(그러나 이 경우 주체의 ID는 개인 정보 보호를 위해 불투명한 임시 식별자 뒤에 숨겨져 있음)를 식별하는
<saml:Subject>요소 - 어설션이 유효한 것으로 간주되어야 하는 조건을 제공하는
<saml:Conditions>요소 - ID 공급자에서 수행된 인증 행위를 설명하는
<saml:AuthnStatement>요소 - 인증된 주체와 관련된 다중 값 속성을 주장하는
<saml:AttributeStatement>요소
간단히 말해, 어설션은 다음 정보를 인코딩한다.
어설션("b07b804c-7c29-ea16-7300-4f3d6f7928ac")은 ID 공급자(https://idp.example.org/SAML2)에 의해 주체(3f7b3dcf-1674-4ecd-92c8-1544f346baf8)에 대해 서비스 공급자(https://sp.example.com/SAML2)만을 위해 "2004-12-05T09:22:05Z"에 발행되었다.
특히 인증 문은 다음을 주장한다.
<saml:Subject>요소에서 식별된 주체는 보호된 채널을 통해 전송된 비밀번호를 사용하여 "2004-12-05T09:22:00Z"에 인증되었다.
마찬가지로 속성 문은 다음을 주장한다.
<saml:Subject>요소에서 식별된 주체는 이 기관에서 '직원' 및 '멤버' 속성을 가지고 있다.
Remove ads
SAML 2.0 프로토콜
요약
관점
다음 프로토콜은 SAMLCore에 지정되어 있다.[1]
- 어설션 질의 및 요청 프로토콜
- 인증 요청 프로토콜
- 아티팩트 해결 프로토콜
- 이름 식별자 관리 프로토콜
- 단일 로그아웃 프로토콜
- 이름 식별자 매핑 프로토콜
이 프로토콜 중 가장 중요한 인증 요청 프로토콜은 아래에 자세히 설명되어 있다.
인증 요청 프로토콜
SAML 1.1 웹 브라우저 SSO 프로필에서는 ID 공급자(IDP)에 의해 시작된다. 즉, 비요청 <samlp:Response> 요소가 ID 공급자에서 서비스 공급자(브라우저를 통해)로 전송된다. (접두사 samlp:는 SAML 프로토콜 네임스페이스를 나타낸다.)
그러나 SAML 2.0에서는 서비스 공급자가 ID 공급자에게 명시적인 인증 요청을 발행하면서 흐름이 시작된다. 결과적으로 인증 요청 프로토콜은 SAML 2.0의 중요한 새로운 기능이다.
주체(또는 주체를 대신하여 작동하는 엔터티)가 인증 문을 포함하는 어설션을 얻으려는 경우 <samlp:AuthnRequest> 요소가 ID 공급자에게 전송된다.
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="aaf23196-1773-2113-474a-fe114412ab72"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z"
AssertionConsumerServiceIndex="0"
AttributeConsumingServiceIndex="0">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>
명시적으로 인증 문을 포함하는 어설션을 요청하는 위의 <samlp:AuthnRequest> 요소는 서비스 공급자(https://sp.example.com/SAML2)에 의해 발행된 후 ID 공급자(브라우저를 통해)에게 제시된 것으로 보인다. ID 공급자는 주체를 인증(필요한 경우)하고 인증 응답을 발행하여 서비스 공급자(다시 브라우저를 통해)에게 다시 전송한다.
아티팩트 해결 프로토콜
SAML 메시지는 값으로 또는 참조로 한 엔터티에서 다른 엔터티로 전송된다. SAML 메시지에 대한 참조를 아티팩트라고 한다. 아티팩트의 수신자는 <samlp:ArtifactResolve> 요청을 아티팩트 발행자에게 직접 전송하여 참조를 해결한다. 그러면 발행자는 아티팩트가 참조하는 실제 메시지로 응답한다.
예를 들어, ID 공급자가 다음 <samlp:ArtifactResolve> 요청을 서비스 공급자에게 직접 전송한다고 가정하자(백 채널을 통해).
<samlp:ArtifactResolve
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_cce4ee769ed970b501d680f697989d14"
Version="2.0"
IssueInstant="2004-12-05T09:21:58Z">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<!-- an ArtifactResolve message SHOULD be signed -->
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<samlp:Artifact>AAQAAMh48/1oXIM+sDo7Dh2qMp1HM4IF5DaRNmDj6RdUmllwn9jJHyEgIi8=</samlp:Artifact>
</samlp:ArtifactResolve>
이에 응답하여 서비스 공급자는 포함된 아티팩트가 참조하는 SAML 요소를 반환한다. 이 프로토콜은 HTTP 아티팩트 바인딩의 기초를 형성한다.
Remove ads
SAML 2.0 바인딩
요약
관점
SAML 2.0이 지원하는 바인딩은 바인딩 사양(SAMLBind[2])에 설명되어 있다.
- SAML SOAP 바인딩 (SOAP 1.1 기반)
- 리버스 SOAP (PAOS) 바인딩
- HTTP 리다이렉트 바인딩
- HTTP POST 바인딩
- HTTP 아티팩트 바인딩
- SAML URI 바인딩
웹 브라우저 SSO의 경우 HTTP 리다이렉트 바인딩과 HTTP POST 바인딩이 일반적으로 사용된다. 예를 들어, 서비스 공급자는 HTTP 리다이렉트를 사용하여 요청을 보내고 ID 공급자는 HTTP POST를 사용하여 응답을 전송할 수 있다. 이 예시는 엔터티의 바인딩 선택이 파트너의 바인딩 선택과 독립적임을 보여준다.
HTTP 리다이렉트 바인딩
SAML 프로토콜 메시지는 HTTP GET 요청의 URL 쿼리 문자열에 직접 전송될 수 있다. 실제 URL 길이에 제한이 있으므로 HTTP 리다이렉트 바인딩은 <samlp:AuthnRequest> 메시지와 같은 짧은 메시지에 적합하다. (SAML 응답과 같이 서명되거나 암호화된 SAML 어설션을 포함하는) 더 긴 메시지는 일반적으로 HTTP POST 바인딩과 같은 다른 바인딩을 통해 전송된다.
HTTP 리다이렉트를 통해 전송되는 SAML 요청 또는 응답은 각각 SAMLRequest 또는 SAMLResponse 쿼리 문자열 매개변수를 갖는다. 메시지가 전송되기 전에 메시지는 압축 해제 (헤더 및 체크섬 없음), base64 인코딩, URL 인코딩 순으로 처리된다. 수신 시에는 원래 메시지를 복구하기 위해 이 프로세스가 역순으로 수행된다.
예를 들어, 위 <samlp:AuthnRequest> 메시지를 인코딩하면 다음이 생성된다.
https://idp.example.org/SAML2/SSO/Redirect?SAMLRequest=fZFfa8IwFMXfBb9DyXvaJtZ1BqsURRC2
Mabbw95ivc5Am3TJrXPffmmLY3%2FA15Pzuyf33On8XJXBCaxTRmeEhTEJQBdmr%2FRbRp63K3pL5rPhYOpkVdY
ib%2FCon%2BC9AYfDQRB4WDvRvWWksVoY6ZQTWlbgBBZik9%2FfCR7GorYGTWFK8pu6DknnwKL%2FWEetlxmR8s
BHbHJDWZqOKGdsRJM0kfQAjCUJ43KX8s78ctnIz%2Blp5xpYa4dSo1fjOKGM03i8jSeCMzGevHa2%2FBK5MNo1F
dgN2JMqPLmHc0b6WTmiVbsGoTf5qv66Zq2t60x0wXZ2RKydiCJXh3CWVV1CWJgqanfl0%2Bin8xutxYOvZL18NK
UqPlvZR5el%2BVhYkAgZQdsA6fWVsZXE63W2itrTQ2cVaKV2CjSSqL1v9P%2FAXv4C
위 메시지(가독성을 위해 서식 지정됨)는 추가 보안을 위해 서명될 수 있다. 실제로는 SP ID를 포함하는 Issuer 및 NameIDPolicy와 같이 <samlp:AuthnRequest>에 포함된 모든 데이터는 IdP와 SP 간에 미리 합의된다(수동 정보 교환 또는 SAML 메타데이터를 통해). 이 경우 요청 서명은 보안 제약이 아니다. <samlp:AuthnRequest>에 Assertion Consumer Service URL과 같이 IdP가 사전에 알지 못하는 정보가 포함된 경우 보안상의 이유로 요청에 서명하는 것이 권장된다.
HTTP POST 바인딩
다음 예시에서는 서비스 공급자와 ID 공급자 모두 HTTP POST 바인딩을 사용한다. 처음에 서비스 공급자는 사용자 에이전트의 요청에 XHTML 양식이 포함된 문서로 응답한다.
<form method="post" action="https://idp.example.org/SAML2/SSO/POST" ...>
<input type="hidden" name="SAMLRequest" value="request" />
... other input parameter....
</form>
SAMLRequest 매개변수의 값은 브라우저를 통해 ID 공급자에게 전송되는 <samlp:AuthnRequest> 요소의 base64 인코딩이다. ID 공급자의 SSO 서비스는 요청을 검증하고 다른 XHTML 양식이 포함된 문서로 응답한다.
<form method="post" action="https://sp.example.com/SAML2/SSO/POST" ...>
<input type="hidden" name="SAMLResponse" value="response" />
...
</form>
SAMLResponse 매개변수의 값은 마찬가지로 브라우저를 통해 서비스 공급자에게 전송되는 <samlp:Response> 요소의 base64 인코딩이다.
폼 제출을 자동화하려면 다음 자바스크립트 코드를 XHTML 페이지의 아무 곳에나 배치할 수 있다.
window.onload = function () { document.forms[0].submit(); }
물론 이는 페이지의 첫 번째 폼 요소에 위의 SAMLResponse를 포함하는 form 요소(forms[0])가 있다고 가정한다.
HTTP 아티팩트 바인딩
HTTP 아티팩트 바인딩은 아티팩트 해결 프로토콜과 SAML SOAP 바인딩(HTTP를 통한)을 사용하여 참조를 통해 SAML 메시지를 해결한다. 다음 구체적인 예시를 살펴보자. 서비스 공급자가 ID 공급자에게 <samlp:AuthnRequest> 메시지를 보내려고 한다고 가정하자. 처음에 서비스 공급자는 HTTP 리다이렉트를 통해 ID 공급자에게 아티팩트를 전송한다.
https://idp.example.org/SAML2/SSO/Artifact?SAMLart=artifact
다음으로 ID 공급자는 백 채널을 통해 <samlp:ArtifactResolve> 요청(이전에 표시된 ArtifactResolveRequest와 같은)을 서비스 공급자에게 직접 보낸다. 마지막으로 서비스 공급자는 참조된 <samlp:AuthnRequest> 메시지를 포함하는 <samlp:ArtifactResponse> 요소를 반환한다.
<samlp:ArtifactResponse
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="_d84a49e5958803dedcff4c984c2b0d95"
InResponseTo="_cce4ee769ed970b501d680f697989d14"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z">
<!-- an ArtifactResponse message SHOULD be signed -->
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<samlp:Status>
<samlp:StatusCode
Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_306f8ec5b618f361c70b6ffb1480eade"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z"
Destination="https://idp.example.org/SAML2/SSO/Artifact"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
AssertionConsumerServiceURL="https://sp.example.com/SAML2/SSO/Artifact">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="false"
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
</samlp:AuthnRequest>
</samlp:ArtifactResponse>
물론 흐름은 다른 방향으로도 갈 수 있다. 즉, ID 공급자가 아티팩트를 발행할 수도 있으며, 사실 이것이 더 일반적이다. 예를 들어, 이 주제의 뒷부분에 나오는 "이중 아티팩트" 프로필 예시를 참조하자.
아티팩트 형식
일반적으로 SAML 2.0 아티팩트는 다음과 같이 정의된다(SAMLBind[2]).
SAML_artifact := B64 (TypeCode EndpointIndex RemainingArtifact) TypeCode := Byte1Byte2 EndpointIndex := Byte1Byte2
따라서 SAML 2.0 아티팩트는 세 가지 구성 요소로 구성된다. 2바이트 TypeCode, 2바이트 EndpointIndex, 그리고 RemainingArtifact라고 하는 임의의 바이트 시퀀스다. 이 세 가지 정보는 연결되어 base64 인코딩되어 완전한 아티팩트를 생성한다.
TypeCode는 아티팩트 형식을 고유하게 식별한다. SAML 2.0은 유형 0x0004의 아티팩트 하나만 미리 정의한다. EndpointIndex는 아티팩트 발행자(이전에 언급했듯이 IdP 또는 SP일 수 있음)가 관리하는 특정 아티팩트 해결 엔드포인트에 대한 참조다. 유형 정의에 의해 결정되는 RemainingArtifact는 아티팩트의 "핵심"이다.
유형 0x0004 아티팩트의 형식은 다음과 같이 추가로 정의된다.
TypeCode := 0x0004 RemainingArtifact := SourceId MessageHandle SourceId := 20-byte_sequence MessageHandle := 20-byte_sequence
따라서 유형 0x0004 아티팩트는 44바이트(인코딩되지 않음) 크기다. SourceId는 임의의 바이트 시퀀스지만, 실제로는 SourceId가 발행자의 entityID의 SHA-1 해시인 경우가 많다. MessageHandle은 아티팩트 발행자가 온디맨드로 생성할 수 있는 SAML 메시지를 참조하는 임의의 바이트 시퀀스다.
예를 들어, 다음 16진수 인코딩된 유형 0x0004 아티팩트를 고려하자.
00040000c878f3fd685c833eb03a3b0e1daa329d47338205e436913660e3e917549a59709fd8c91f2120222f
자세히 보면 아티팩트 앞부분에 TypeCode (0x0004)와 EndpointIndex (0x0000)를 볼 수 있다. 다음 20바이트는 발행자의 entityID(https://idp.example.org/SAML2)의 SHA-1 해시이며, 그 뒤에 20개의 임의 바이트가 온다. 이 44바이트의 base64 인코딩이 위 ArtifactResolveRequest 예시에서 볼 수 있는 내용이다.
Remove ads
SAML 2.0 프로필
요약
관점
SAML 2.0은 SAML 1.1과 마찬가지로 여전히 웹 브라우저 SSO가 주요 사용 사례지만, SAML 2.0의 범위는 다음의 광범위한 프로필 목록에서 알 수 있듯이 이전 SAML 버전보다 더 넓다.
- SSO 프로필
- 웹 브라우저 SSO 프로필
- 확장 클라이언트 또는 프록시(ECP) 프로필
- ID 공급자 발견 프로필
- 단일 로그아웃 프로필
- 이름 식별자 관리 프로필
- 아티팩트 해결 프로필
- 어설션 질의/요청 프로필
- 이름 식별자 매핑 프로필
- SAML 속성 프로필
- 기본 속성 프로필
- X.500/LDAP 속성 프로필
- UUID 속성 프로필
- DCE PAC 속성 프로필
- XACML 속성 프로필
지원되는 프로필 수가 상당히 많지만, 각 프로필의 바인딩 측면이 별도의 바인딩 사양(SAMLBind[2])으로 분리되었으므로 프로필 사양(SAMLProf[3])은 간소화되었다.
웹 브라우저 SSO 프로필
SAML 2.0은 ID 공급자(IdP), 서비스 공급자(SP) 및 HTTP 사용자 에이전트를 사용하는 주체를 포함하는 웹 브라우저 SSO 프로필을 지정한다. 서비스 공급자는 네 가지 바인딩 중에서 선택할 수 있으며, ID 공급자는 세 가지 바인딩 중에서 선택할 수 있어 12가지 가능한 배포 시나리오가 발생한다. 아래에서는 세 가지 배포 시나리오를 설명한다.
SP 리다이렉트 요청; IdP POST 응답
이것은 가장 일반적인 시나리오 중 하나다. 서비스 공급자는 HTTP-리다이렉트 바인딩을 사용하여 SAML 요청을 IdP SSO 서비스로 보낸다. ID 공급자는 HTTP-POST 바인딩을 사용하여 SAML 응답을 SP 어설션 소비자 서비스로 반환한다.

메시지 흐름은 서비스 공급자의 보안 리소스 요청으로 시작된다.
1. SP에서 대상 리소스 요청
주체(HTTP 사용자 에이전트를 통해)는 서비스 공급자에서 대상 리소스를 요청한다.
https://sp.example.com/myresource
서비스 공급자는 대상 리소스를 대신하여 보안 검사를 수행한다. 서비스 공급자에 유효한 보안 컨텍스트가 이미 존재하면 2-7단계를 건너뛴다.
서비스 공급자는 사용될 ID 공급자를 발견하기 위해 사용자에게 질문하거나 미리 구성된 IdP를 사용하는 등 모든 종류의 메커니즘을 사용할 수 있다.
2. IdP SSO 서비스로 리다이렉트
서비스 공급자는 적절한 SAMLRequest(및 RelayState, 있는 경우)를 생성한 다음 표준 HTTP 302 리다이렉트를 사용하여 브라우저를 IdP SSO 서비스로 리다이렉트한다.
302 Redirect
Location: https://idp.example.org/SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token
RelayState 토큰은 서비스 공급자에서 유지 관리되는 상태 정보에 대한 불투명한 참조다. SAMLRequest 매개변수의 값은 <samlp:AuthnRequest> 요소의 압축 해제, base64 인코딩 및 URL 인코딩된 값이다.
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_1"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z"
AssertionConsumerServiceIndex="0">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>
SAMLRequest는 SP 서명 키를 사용하여 서명될 수 있다. 그러나 일반적으로 이는 필요하지 않다.
3. IdP에서 SSO 서비스 요청
사용자 에이전트는 ID 공급자의 SSO 서비스에 GET 요청을 발행한다.
GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token HTTP/1.1
Host: idp.example.org
여기서 SAMLRequest 및 RelayState 매개변수의 값은 리다이렉트에서 제공된 값과 동일하다. ID 공급자의 SSO 서비스는 <samlp:AuthnRequest> 요소를 처리(URL 디코딩, base64 디코딩, 압축 해제 순서로)하고 보안 검사를 수행한다. 사용자에게 유효한 보안 컨텍스트가 없으면 ID 공급자는 임의의 메커니즘(세부 정보 생략)으로 사용자를 식별한다.
4. XHTML 양식으로 응답
SSO 서비스는 요청을 검증하고 XHTML 양식이 포함된 문서로 응답한다.
<form method="post" action="https://sp.example.com/SAML2/SSO/POST" ...>
<input type="hidden" name="SAMLResponse" value="response" />
<input type="hidden" name="RelayState" value="token" />
...
<input type="submit" value="Submit" />
</form>
RelayState 매개변수 값은 3단계에서 보존되었다. SAMLResponse 매개변수 값은 다음 <samlp:Response> 요소의 base64 인코딩이다.
<samlp:Response
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_2"
InResponseTo="identifier_1"
Version="2.0"
IssueInstant="2004-12-05T09:22:05Z"
Destination="https://sp.example.com/SAML2/SSO/POST">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<samlp:Status>
<samlp:StatusCode
Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_3"
Version="2.0"
IssueInstant="2004-12-05T09:22:05Z">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<!-- a POSTed assertion MUST be signed -->
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<saml:Subject>
<saml:NameID
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
3f7b3dcf-1674-4ecd-92c8-1544f346baf8
</saml:NameID>
<saml:SubjectConfirmation
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
InResponseTo="identifier_1"
Recipient="https://sp.example.com/SAML2/SSO/POST"
NotOnOrAfter="2004-12-05T09:27:05Z"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions
NotBefore="2004-12-05T09:17:05Z"
NotOnOrAfter="2004-12-05T09:27:05Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.com/SAML2</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement
AuthnInstant="2004-12-05T09:22:00Z"
SessionIndex="identifier_3">
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
5. SP에서 어설션 소비자 서비스 요청
사용자 에이전트는 서비스 공급자의 어설션 소비자 서비스에 POST 요청을 발행한다.
POST /SAML2/SSO/POST HTTP/1.1
Host: sp.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: nnn
SAMLResponse=response&RelayState=token
여기서 SAMLResponse 및 RelayState 매개변수의 값은 4단계의 XHTML 양식에서 가져온다.
6. 대상 리소스로 리다이렉트
어설션 소비자 서비스는 응답을 처리하고 서비스 공급자에 보안 컨텍스트를 생성한 다음 사용자 에이전트를 대상 리소스로 리다이렉트한다.
7. SP에서 대상 리소스 다시 요청
사용자 에이전트는 서비스 공급자에서 대상 리소스를 다시 요청한다.
https://sp.example.com/myresource
8. 요청된 리소스로 응답
보안 컨텍스트가 존재하므로 서비스 공급자는 리소스를 사용자 에이전트에 반환한다.
SP POST 요청; IdP POST 응답
이것은 서비스 공급자(SP)와 ID 공급자(IdP) 모두 HTTP POST 바인딩을 사용하는 SAML 2.0 웹 브라우저 SSO 프로필(SAMLProf[3])의 비교적 간단한 배포다.

메시지 흐름은 SP의 보안 리소스 요청으로 시작된다.
1. SP에서 대상 리소스 요청
주체(HTTP 사용자 에이전트를 통해)는 서비스 공급자에서 대상 리소스를 요청한다.
https://sp.example.com/myresource
서비스 공급자는 대상 리소스를 대신하여 보안 검사를 수행한다. 서비스 공급자에 유효한 보안 컨텍스트가 이미 존재하면 2-7단계를 건너뛴다.
2. XHTML 양식으로 응답
서비스 공급자는 XHTML 양식이 포함된 문서로 응답한다.
<form method="post" action="https://idp.example.org/SAML2/SSO/POST" ...>
<input type="hidden" name="SAMLRequest" value="request" />
<input type="hidden" name="RelayState" value="token" />
...
<input type="submit" value="Submit" />
</form>
RelayState 토큰은 서비스 공급자에서 유지 관리되는 상태 정보에 대한 불투명한 참조다. SAMLRequest 매개변수의 값은 다음 <samlp:AuthnRequest> 요소의 base64 인코딩이다.
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_1"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z"
AssertionConsumerServiceIndex="0">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>
<samlp:AuthnRequest> 요소가 XHTML 양식에 삽입되기 전에 먼저 base64 인코딩된다.
3. IdP에서 SSO 서비스 요청
사용자 에이전트는 ID 공급자의 SSO 서비스에 POST 요청을 발행한다.
POST /SAML2/SSO/POST HTTP/1.1
Host: idp.example.org
Content-Type: application/x-www-form-urlencoded
Content-Length: nnn
SAMLRequest=request&RelayState=token
여기서 SAMLRequest 및 RelayState 매개변수의 값은 2단계의 XHTML 양식에서 가져온다. SSO 서비스는 <samlp:AuthnRequest> 요소를 처리(URL 디코딩, base64 디코딩, 압축 해제 순서로)하고 보안 검사를 수행한다. 사용자에게 유효한 보안 컨텍스트가 없으면 ID 공급자는 사용자를 식별한다(세부 정보 생략).
4. XHTML 양식으로 응답
SSO 서비스는 요청을 검증하고 XHTML 양식이 포함된 문서로 응답한다.
<form method="post" action="https://sp.example.com/SAML2/SSO/POST" ...>
<input type="hidden" name="SAMLResponse" value="response" />
<input type="hidden" name="RelayState" value="token" />
...
<input type="submit" value="Submit" />
</form>
RelayState 매개변수 값은 3단계에서 보존되었다. SAMLResponse 매개변수 값은 다음 <samlp:Response> 요소의 base64 인코딩이다.
<samlp:Response
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_2"
InResponseTo="identifier_1"
Version="2.0"
IssueInstant="2004-12-05T09:22:05Z"
Destination="https://sp.example.com/SAML2/SSO/POST">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<samlp:Status>
<samlp:StatusCode
Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_3"
Version="2.0"
IssueInstant="2004-12-05T09:22:05Z">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<!-- a POSTed assertion MUST be signed -->
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<saml:Subject>
<saml:NameID
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
3f7b3dcf-1674-4ecd-92c8-1544f346baf8
</saml:NameID>
<saml:SubjectConfirmation
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
InResponseTo="identifier_1"
Recipient="https://sp.example.com/SAML2/SSO/POST"
NotOnOrAfter="2004-12-05T09:27:05Z"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions
NotBefore="2004-12-05T09:17:05Z"
NotOnOrAfter="2004-12-05T09:27:05Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.com/SAML2</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement
AuthnInstant="2004-12-05T09:22:00Z"
SessionIndex="identifier_3">
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
5. SP에서 어설션 소비자 서비스 요청
사용자 에이전트는 서비스 공급자의 어설션 소비자 서비스에 POST 요청을 발행한다.
POST /SAML2/SSO/POST HTTP/1.1
Host: sp.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: nnn
SAMLResponse=response&RelayState=token
여기서 SAMLResponse 및 RelayState 매개변수의 값은 4단계의 XHTML 양식에서 가져온다.
6. 대상 리소스로 리다이렉트
어설션 소비자 서비스는 응답을 처리하고 서비스 공급자에 보안 컨텍스트를 생성한 다음 사용자 에이전트를 대상 리소스로 리다이렉트한다.
7. SP에서 대상 리소스 다시 요청
사용자 에이전트는 서비스 공급자에서 대상 리소스를 다시 요청한다.
https://sp.example.com/myresource
8. 요청된 리소스로 응답
보안 컨텍스트가 존재하므로 서비스 공급자는 리소스를 사용자 에이전트에 반환한다.
SP 리다이렉트 아티팩트; IdP 리다이렉트 아티팩트
이것은 서비스 공급자(SP)와 ID 공급자(IdP) 모두 HTTP 아티팩트 바인딩을 사용하는 SAML 2.0 웹 브라우저 SSO 프로필(SAMLProf[3])의 복잡한 배포다. 두 아티팩트 모두 HTTP GET을 통해 해당 엔드포인트로 전달된다.

메시지 흐름은 SP의 보안 리소스 요청으로 시작된다.
1. SP에서 대상 리소스 요청
주체(HTTP 사용자 에이전트를 통해)는 서비스 공급자에서 대상 리소스를 요청한다.
https://sp.example.com/myresource
서비스 공급자는 대상 리소스를 대신하여 보안 검사를 수행한다. 서비스 공급자에 유효한 보안 컨텍스트가 이미 존재하면 2-11단계를 건너뛴다.
2. IdP의 단일 로그인(SSO) 서비스로 리다이렉트
서비스 공급자는 사용자 에이전트를 ID 공급자의 단일 로그인(SSO) 서비스로 리다이렉트한다. RelayState 매개변수와 SAMLart 매개변수가 리다이렉트 URL에 추가된다.
3. IdP에서 SSO 서비스 요청
사용자 에이전트는 ID 공급자의 SSO 서비스를 요청한다.
https://idp.example.org/SAML2/SSO/Artifact?SAMLart=artifact_1&RelayState=token
여기서 token은 서비스 공급자에서 유지 관리되는 상태 정보에 대한 불투명한 참조이고, artifact_1은 2단계에서 발행된 SAML 아티팩트다.
4. SP에서 아티팩트 해결 서비스 요청
SSO 서비스는 <samlp:ArtifactResolve> 요소를 SAML SOAP 메시지에 바인딩하여 서비스 공급자의 아티팩트 해결 서비스에 전송함으로써 아티팩트의 참조를 해제한다.
<samlp:ArtifactResolve
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_1"
Version="2.0"
IssueInstant="2004-12-05T09:21:58Z"
Destination="https://sp.example.com/SAML2/ArtifactResolution">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<!-- an ArtifactResolve message SHOULD be signed -->
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<samlp:Artifact>artifact_1</samlp:Artifact>
</samlp:ArtifactResolve>
여기서 <samlp:Artifact> 요소의 값은 3단계에서 전송된 SAML 아티팩트다.
5. SAML AuthnRequest로 응답
서비스 공급자의 아티팩트 해결 서비스는 <samlp:ArtifactResponse> 요소(<samlp:AuthnRequest> 요소 포함)를 SAML SOAP 메시지에 바인딩하여 ID 공급자의 SSO 서비스에 반환한다.
<samlp:ArtifactResponse
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="identifier_2"
InResponseTo="identifier_1"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z">
<!-- an ArtifactResponse message SHOULD be signed -->
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<samlp:Status>
<samlp:StatusCode
Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_3"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z"
Destination="https://idp.example.org/SAML2/SSO/Artifact"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
AssertionConsumerServiceURL="https://sp.example.com/SAML2/SSO/Artifact">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="false"
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
</samlp:AuthnRequest>
</samlp:ArtifactResponse>
SSO 서비스는 <samlp:AuthnRequest> 요소를 처리하고 보안 검사를 수행한다. 사용자에게 유효한 보안 컨텍스트가 없으면 ID 공급자는 사용자를 식별한다(세부 정보 생략).
6. 어설션 소비자 서비스로 리다이렉트
ID 공급자의 SSO 서비스는 사용자 에이전트를 서비스 공급자의 어설션 소비자 서비스로 리다이렉트한다. 이전 RelayState 매개변수와 새 SAMLart 매개변수가 리다이렉트 URL에 추가된다.
7. SP에서 어설션 소비자 서비스 요청
사용자 에이전트는 서비스 공급자의 어설션 소비자 서비스를 요청한다.
https://sp.example.com/SAML2/SSO/Artifact?SAMLart=artifact_2&RelayState=token
여기서 token은 3단계의 토큰 값이고, artifact_2는 6단계에서 발행된 SAML 아티팩트다.
8. IdP에서 아티팩트 해결 서비스 요청
어설션 소비자 서비스는 <samlp:ArtifactResolve> 요소를 SAML SOAP 메시지에 바인딩하여 ID 공급자의 아티팩트 해결 서비스에 전송함으로써 아티팩트의 참조를 해제한다.
<samlp:ArtifactResolve
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_4"
Version="2.0"
IssueInstant="2004-12-05T09:22:04Z"
Destination="https://idp.example.org/SAML2/ArtifactResolution">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<!-- an ArtifactResolve message SHOULD be signed -->
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<samlp:Artifact>artifact_2</samlp:Artifact>
</samlp:ArtifactResolve>
여기서 <samlp:Artifact> 요소의 값은 7단계에서 전송된 SAML 아티팩트다.
9. SAML 어설션으로 응답
ID 공급자의 아티팩트 해결 서비스는 <samlp:ArtifactResponse> 요소(<samlp:Response> 요소 포함)를 SAML SOAP 메시지에 바인딩하여 서비스 공급자의 어설션 소비자 서비스에 반환한다.
<samlp:ArtifactResponse
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="identifier_5"
InResponseTo="identifier_4"
Version="2.0"
IssueInstant="2004-12-05T09:22:05Z">
<!-- an ArtifactResponse message SHOULD be signed -->
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<samlp:Status>
<samlp:StatusCode
Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<samlp:Response
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_6"
InResponseTo="identifier_3"
Version="2.0"
IssueInstant="2004-12-05T09:22:05Z"
Destination="https://sp.example.com/SAML2/SSO/Artifact">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
<samlp:Status>
<samlp:StatusCode
Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_7"
Version="2.0"
IssueInstant="2004-12-05T09:22:05Z">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<!-- a Subject element is required -->
<saml:Subject>
<saml:NameID
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
user@mail.example.org
</saml:NameID>
<saml:SubjectConfirmation
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
InResponseTo="identifier_3"
Recipient="https://sp.example.com/SAML2/SSO/Artifact"
NotOnOrAfter="2004-12-05T09:27:05Z"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions
NotBefore="2004-12-05T09:17:05Z"
NotOnOrAfter="2004-12-05T09:27:05Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.com/SAML2</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement
AuthnInstant="2004-12-05T09:22:00Z"
SessionIndex="identifier_7">
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
</samlp:ArtifactResponse>
10. 대상 리소스로 리다이렉트
어설션 소비자 서비스는 응답을 처리하고 서비스 공급자에 보안 컨텍스트를 생성한 다음 사용자 에이전트를 대상 리소스로 리다이렉트한다.
11. SP에서 대상 리소스 다시 요청
사용자 에이전트는 서비스 공급자에서 대상 리소스를 다시 요청한다.
https://sp.example.com/myresource
12. 요청된 리소스로 응답
보안 컨텍스트가 존재하므로 서비스 공급자는 리소스를 사용자 에이전트에 반환한다.
ID 공급자 발견 프로필
SAML 2.0 ID 공급자 발견 프로필은 다음 개념을 소개한다.
- 공통 도메인
- 공통 도메인 쿠키
- 공통 도메인 쿠키 쓰기 서비스
- 공통 도메인 쿠키 읽기 서비스
가상의 공통 도메인 예시로, Example UK (example.co.uk)와 Example Deutschland (example.de)가 가상 조직인 Example Global Alliance (example.com)에 속한다고 가정하자. 이 예시에서 도메인 example.com은 공통 도메인이다. Example UK와 Example Deutschland 모두 이 도메인에 존재한다(각각 uk.example.com 및 de.example.com).
공통 도메인 쿠키는 공통 도메인 범위의 보안 브라우저 쿠키다. 각 브라우저 사용자에게 이 쿠키는 최근 방문한 IdP의 기록 목록을 저장한다. 쿠키의 이름과 값은 IdP 발견 프로필(SAMLProf[3])에 지정되어 있다.
성공적인 인증 행위 후에 IdP는 공통 도메인 쿠키 쓰기 서비스를 요청한다. 이 서비스는 IdP의 고유 식별자를 공통 도메인 쿠키에 추가한다. SP는 보호된 리소스에 대한 인증되지 않은 요청을 받으면 공통 도메인 쿠키 읽기 서비스를 요청하여 브라우저 사용자의 가장 최근에 사용한 IdP를 발견한다.
어설션 질의/요청 프로필
어설션 질의/요청 프로필은 다음 SAML 2.0 요소를 사용하여 수많은 유형의 소위 질의를 수용하는 일반적인 프로필이다.
- 고유 식별자(
ID)가 주어진 어설션을 요청하는 데 사용되는<samlp:AssertionIDRequest>요소 - 새로운 주체 기반 SAML 질의를 정의할 수 있는 추상 확장 지점인
<samlp:SubjectQuery>요소 - 특정 주체에 대한 기존 인증 어설션을 인증 기관에 요청하는 데 사용되는
<samlp:AuthnQuery>요소 - 특정 주체에 대한 속성을 속성 기관에 요청하는 데 사용되는
<samlp:AttributeQuery>요소 - 신뢰할 수 있는 제3자에게 권한 부여 결정을 요청하는 데 사용되는
<samlp:AuthzDecisionQuery>요소
SAML SOAP 바인딩은 종종 질의와 함께 사용된다.
SAML 속성 질의
속성 질의는 아마도 가장 중요한 유형의 SAML 질의일 것이다. 종종 주체를 대신하여 요청자가 속성을 ID 공급자에게 질의한다. 아래에서는 주체가 직접 발행한 질의의 예시를 보여준다.
<samlp:AttributeQuery
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="aaf23196-1773-2113-474a-fe114412ab72"
Version="2.0"
IssueInstant="2006-07-17T20:31:40Z">
<saml:Issuer
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName">
CN=trscavo@example.com,OU=User,O=NCSA-TEST,C=US
</saml:Issuer>
<saml:Subject>
<saml:NameID
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName">
CN=trscavo@example.com,OU=User,O=NCSA-TEST,C=US
</saml:NameID>
</saml:Subject>
<saml:Attribute
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:2.5.4.42"
FriendlyName="givenName">
</saml:Attribute>
<saml:Attribute
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:1.3.6.1.4.1.1466.115.121.1.26"
FriendlyName="mail">
</saml:Attribute>
</samlp:AttributeQuery>
이 경우 Issuer가 Subject임을 주목하자. 이것을 속성 자체 질의(attribute self-query)라고 부르기도 한다. ID 공급자는 <samlp:Response> 요소(표시되지 않음)에 래핑된 다음 어설션을 반환할 수 있다.
<saml:Assertion
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
ID="_33776a319493ad607b7ab3e689482e45"
Version="2.0"
IssueInstant="2006-07-17T20:31:41Z">
<saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
<ds:Signature>...</ds:Signature>
<saml:Subject>
<saml:NameID
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName">
CN=trscavo@example.com,OU=User,O=NCSA-TEST,C=US
</saml:NameID>
<saml:SubjectConfirmation
Method="urn:oasis:names:tc:SAML:2.0:cm:holder-of-key">
<saml:SubjectConfirmationData>
<ds:KeyInfo>
<ds:X509Data>
<!-- principal's X.509 cert -->
<ds:X509Certificate>
MIICiDCCAXACCQDE+9eiWrm62jANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJV
UzESMBAGA1UEChMJTkNTQS1URVNUMQ0wCwYDVQQLEwRVc2VyMRMwEQYDVQQDEwpT
UC1TZXJ2aWNlMB4XDTA2MDcxNzIwMjE0MVoXDTA2MDcxODIwMjE0MVowSzELMAkG
A1UEBhMCVVMxEjAQBgNVBAoTCU5DU0EtVEVTVDENMAsGA1UECxMEVXNlcjEZMBcG
A1UEAwwQdHJzY2F2b0B1aXVjLmVkdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
gYEAv9QMe4lRl3XbWPcflbCjGK9gty6zBJmp+tsaJINM0VaBaZ3t+tSXknelYife
nCc2O3yaX76aq53QMXy+5wKQYe8Rzdw28Nv3a73wfjXJXoUhGkvERcscs9EfIWcC
g2bHOg8uSh+Fbv3lHih4lBJ5MCS2buJfsR7dlr/xsadU2RcCAwEAATANBgkqhkiG
9w0BAQQFAAOCAQEAdyIcMTob7TVkelfJ7+I1j0LO24UlKvbLzd2OPvcFTCv6fVHx
Ejk0QxaZXJhreZ6+rIdiMXrEzlRdJEsNMxtDW8++sVp6avoB5EX1y3ez+CEAIL4g
cjvKZUR4dMryWshWIBHKFFul+r7urUgvWI12KbMeE9KP+kiiiiTskLcKgFzngw1J
selmHhTcTCrcDocn5yO2+d3dog52vSOtVFDBsBuvDixO2hv679JR6Hlqjtk4GExp
E9iVI0wdPE038uQIJJTXlhsMMLvUGVh/c0ReJBn92Vj4dI/yy6PtY/8ncYLYNkjg
oVN0J/ymOktn9lTlFyTiuY4OuJsZRO1+zWLy9g==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</saml:SubjectConfirmationData>
</saml:SubjectConfirmation>
</saml:Subject>
<!-- assertion lifetime constrained by principal's X.509 cert -->
<saml:Conditions
NotBefore="2006-07-17T20:31:41Z"
NotOnOrAfter="2006-07-18T20:21:41Z">
</saml:Conditions>
<saml:AuthnStatement
AuthnInstant="2006-07-17T20:31:41Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
x500:Encoding="LDAP"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:2.5.4.42"
FriendlyName="givenName">
<saml:AttributeValue
xsi:type="xs:string">Tom</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
x500:Encoding="LDAP"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:1.3.6.1.4.1.1466.115.121.1.26"
FriendlyName="mail">
<saml:AttributeValue
xsi:type="xs:string">trscavo@example.org</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
이전에 표시된 전달자 어설션과 대조적으로, 이 어설션은 주체가 ID 공급자에 인증하는 데 사용한 X.509 인증서의 수명에 해당하는 더 긴 수명을 갖는다. 또한 어설션이 서명되었으므로 사용자는 이 어설션을 의존 당사자에게 푸시할 수 있으며, 사용자가 해당 개인 키의 소유를 증명할 수 있는 한("홀더-오브-키"라는 이름이 붙은 이유) 의존 당사자는 어설션이 정품임을 확신할 수 있다.
Remove ads
SAML 2.0 메타데이터
요약
관점
말 그대로 메타데이터는 SAML이 작동(또는 잘 작동)하게 하는 요소다. 메타데이터의 몇 가지 중요한 용도는 다음과 같다.
- 서비스 공급자가 브라우저를 통해 ID 공급자에게
<samlp:AuthnRequest>요소를 전송할 준비를 한다. 서비스 공급자는 ID 공급자가 정품이며 사용자의 비밀번호를 피싱하려는 악의적인 ID 공급자가 아님을 어떻게 아는가? 서비스 공급자는 인증 요청을 발행하기 전에 메타데이터에 있는 신뢰할 수 있는 ID 공급자 목록을 참조한다. - 이전 시나리오에서 서비스 공급자는 인증 요청과 함께 사용자를 어디로 보내야 할지 어떻게 아는가? 서비스 공급자는 메타데이터에 있는 신뢰할 수 있는 ID 공급자의 미리 정해진 엔드포인트 위치를 조회한다.
- ID 공급자가 브라우저를 통해 서비스 공급자로부터
<samlp:AuthnRequest>요소를 수신한다. ID 공급자는 서비스 공급자가 정품이며 사용자 개인 개인 식별 정보를 수집하려는 악의적인 서비스 공급자가 아님을 어떻게 아는가? ID 공급자는 인증 응답을 발행하기 전에 메타데이터에 있는 신뢰할 수 있는 서비스 공급자 목록을 참조한다. - 이전 시나리오에서 ID 공급자는 신뢰할 수 있는 서비스 공급자(그리고 신뢰할 수 있는 서비스 공급자만)가 어설션을 해독할 수 있도록 SAML 어설션을 어떻게 암호화하는가? ID 공급자는 메타데이터에 있는 서비스 공급자의 암호화 인증서를 사용하여 어설션을 암호화한다.
- 이전 시나리오를 계속하여, ID 공급자는 인증 응답과 함께 사용자를 어디로 보내야 할지 어떻게 아는가? ID 공급자는 메타데이터에 있는 신뢰할 수 있는 서비스 공급자의 미리 정해진 엔드포인트 위치를 조회한다.
- 서비스 공급자는 인증 응답이 신뢰할 수 있는 ID 공급자로부터 온 것임을 어떻게 아는가? 서비스 공급자는 메타데이터에서 가져온 ID 공급자의 공개 키를 사용하여 어설션의 서명을 확인한다.
- 서비스 공급자는 신뢰할 수 있는 ID 공급자로부터 수신한 아티팩트를 어디에서 해결해야 하는지 어떻게 아는가? 서비스 공급자는 메타데이터에서 ID 공급자의 아티팩트 해결 서비스의 미리 정해진 엔드포인트 위치를 조회한다.
메타데이터는 ID 공급자와 서비스 공급자 간의 안전한 트랜잭션을 보장한다. 메타데이터 이전에는 신뢰 정보가 독점적인 방식으로 구현에 인코딩되었다. 이제 신뢰 정보 공유는 표준 메타데이터를 통해 용이해졌다. SAML 2.0은 엔터티가 신뢰 프로세스를 부트스트랩하는 데 활용할 수 있는 잘 정의되고 상호 운용 가능한 메타데이터 형식을 제공한다.
ID 공급자 메타데이터
ID 공급자는 <md:EntityDescriptor> 요소에 자신에 대한 데이터를 게시한다.
<md:EntityDescriptor entityID="https://idp.example.org/SAML2" validUntil="2013-03-22T23:00:00Z"
xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<!-- insert ds:Signature element (omitted) -->
<!-- insert md:IDPSSODescriptor element (below) -->
<md:Organization>
<md:OrganizationName xml:lang="en">Some Non-profit Organization of New York</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">Some Non-profit Organization</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">https://www.example.org/</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:SurName>SAML Technical Support</md:SurName>
<md:EmailAddress>mailto:saml-support@example.org</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor>
이 엔터티 디스크립터에 대한 다음 세부 사항에 주목하자.
entityID속성은 엔터티의 고유 식별자다.validUntil속성은 메타데이터의 만료 날짜를 제공한다.<ds:Signature>요소(단순화를 위해 생략됨)는 메타데이터의 진위성과 무결성을 보장하는 디지털 서명을 포함한다.<md:Organization>요소에 식별된 조직은 엔터티 디스크립터에 의해 설명된 "엔터티에 대한 책임이 있다"(SAMLMeta[4] 섹션 2.3.2).<md:ContactPerson>요소의 연락처 정보는 엔터티를 담당하는 기술 담당자를 식별한다. 여러 연락처 및 연락처 유형이 가능하다. SAMLMeta[4] 섹션 2.3.2.2를 참조하자.
정의상 ID 공급자는 SAMLProf에 지정된 SAML 웹 브라우저 SSO 프로필을 지원하는 SSO 서비스를 관리한다.[3] 예를 들어 다음 섹션에 표시된 <md:IDPSSODescriptor> 요소에 설명된 ID 공급자를 참조하자.
SSO 서비스 메타데이터
ID 공급자의 SSO 서비스는 <md:IDPSSODescriptor> 요소에 설명되어 있다.
<md:IDPSSODescriptor
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo>...</ds:KeyInfo>
</md:KeyDescriptor>
<md:ArtifactResolutionService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="https://idp.example.org/SAML2/ArtifactResolution"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://idp.example.org/SAML2/SSO/Redirect"/>
<md:SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://idp.example.org/SAML2/SSO/POST"/>
<md:SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="https://idp.example.org/SAML2/Artifact"/>
<saml:Attribute
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1"
FriendlyName="eduPersonAffiliation">
<saml:AttributeValue>member</saml:AttributeValue>
<saml:AttributeValue>student</saml:AttributeValue>
<saml:AttributeValue>faculty</saml:AttributeValue>
<saml:AttributeValue>employee</saml:AttributeValue>
<saml:AttributeValue>staff</saml:AttributeValue>
</saml:Attribute>
</md:IDPSSODescriptor>
이전 메타데이터 요소는 ID 공급자의 SSO 서비스를 설명한다. 이 요소에 대한 다음 세부 사항에 주목하자.
- ID 공급자 소프트웨어는 개인 SAML 서명 키 및 개인 백채널 TLS 키로 구성된다. 해당 공개 키는 IdP 메타데이터의
<md:KeyDescriptor use="signing">요소에 포함된다. 키 자료는 간결성을 위해 키 디스크립터에서 생략되었다. <md:ArtifactResolutionService>요소의Binding속성은 SAML SOAP 바인딩(SAMLBind[2])이 아티팩트 해결에 사용되어야 함을 나타낸다.<md:ArtifactResolutionService>요소의Location속성은 "이중 아티팩트" 프로필의 8단계에서 사용된다.<md:ArtifactResolutionService>요소의index속성 값은 SAML 유형 0x0004 아티팩트를 구성할 때EndpointIndex값으로 사용된다.<md:NameIDFormat>요소는 SSO 서비스가 지원하는 SAML 이름 식별자 형식(SAMLCore[1])을 나타낸다.<md:SingleSignOnService>요소의Binding속성은 SAML 2.0 바인딩 사양(SAMLBind[2])에 지정된 표준 URI다.- HTTP POST 바인딩을 지원하는
<md:SingleSignOnService>요소의Location속성은 "이중 POST" 프로필의 2단계에서 사용된다. - HTTP 아티팩트 바인딩을 지원하는
<md:SingleSignOnService>요소의Location속성은 "이중 아티팩트" 프로필의 2단계에서 사용된다. <saml:Attribute>요소는 ID 공급자가 주장할 의향이 있는 속성(정책에 따라)을 설명한다.<saml:AttributeValue>요소는 속성이 가질 수 있는 가능한 값을 열거한다.
이 섹션 시작 부분에 언급된 대로, Location 속성 값은 서비스 공급자가 SAML 메시지를 라우팅하는 데 사용되며, 이는 악의적인 ID 공급자가 중간자 공격을 조직할 가능성을 최소화한다.
서비스 공급자 메타데이터
ID 공급자와 마찬가지로 서비스 공급자도 <md:EntityDescriptor> 요소에 자신에 대한 데이터를 게시한다.
<md:EntityDescriptor entityID="https://sp.example.com/SAML2" validUntil="2013-03-22T23:00:00Z"
xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<!-- insert ds:Signature element (omitted) -->
<!-- insert md:SPSSODescriptor element (see below) -->
<md:Organization>
<md:OrganizationName xml:lang="en">Some Commercial Vendor of California</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">Some Commercial Vendor</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">https://www.example.com/</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:SurName>SAML Technical Support</md:SurName>
<md:EmailAddress>mailto:saml-support@example.com</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor>
이 엔터티 디스크립터에 대한 다음 세부 사항에 주목하자.
entityID속성은 엔터티의 고유 식별자다.validUntil속성은 메타데이터의 만료 날짜를 제공한다.<ds:Signature>요소(단순화를 위해 생략됨)는 메타데이터의 진위성과 무결성을 보장하는 디지털 서명을 포함한다.<md:Organization>요소에 식별된 조직은 엔터티 디스크립터에 의해 설명된 "엔터티에 대한 책임이 있다"(SAMLMeta[4] 섹션 2.3.2).<md:ContactPerson>요소의 연락처 정보는 엔터티를 담당하는 기술 담당자를 식별한다. 여러 연락처 및 연락처 유형이 가능하다. SAMLMeta[4] 섹션 2.3.2.2를 참조하자.
정의상 서비스 공급자는 SAMLProf에 지정된 SAML 웹 브라우저 SSO 프로필을 지원하는 어설션 소비자 서비스를 관리한다.[3] 예를 들어 다음 섹션에 표시된 <md:SPSSODescriptor> 요소에 설명된 서비스 공급자를 참조하자.
어설션 소비자 서비스 메타데이터
어설션 소비자 서비스는 <md:SPSSODescriptor> 요소에 포함되어 있다.
<md:SPSSODescriptor
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo>...</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo>...</ds:KeyInfo>
</md:KeyDescriptor>
<md:ArtifactResolutionService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="https://sp.example.com/SAML2/ArtifactResolution"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:AssertionConsumerService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://sp.example.com/SAML2/SSO/POST"/>
<md:AssertionConsumerService index="1"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="https://sp.example.com/SAML2/Artifact"/>
<md:AttributeConsumingService isDefault="true" index="1">
<md:ServiceName xml:lang="en">Service Provider Portal</md:ServiceName>
<md:RequestedAttribute
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1"
FriendlyName="eduPersonAffiliation">
</md:RequestedAttribute>
</md:AttributeConsumingService>
</md:SPSSODescriptor>
<md:SPSSODescriptor> 메타데이터 요소에 대한 다음 세부 사항에 주목하자.
- 서비스 공급자 소프트웨어는 개인 SAML 서명 키 및 개인 백채널 TLS 키로 구성된다. 해당 공개 키는 SP 메타데이터의
<md:KeyDescriptor use="signing">요소에 포함된다. 키 자료는 간결성을 위해 키 디스크립터에서 생략되었다. - 마찬가지로 서비스 공급자 소프트웨어는 개인 SAML 암호 해독 키로 구성된다. 공개 SAML 암호화 키는 SP 메타데이터의
<md:KeyDescriptor use="encryption">요소에 포함된다. 키 자료는 간결성을 위해 키 디스크립터에서 생략되었다. <md:AssertionConsumerService>요소의index속성은<samlp:AuthnRequest>요소의AssertionConsumerServiceIndex속성 값으로 사용된다.<md:AssertionConsumerService>요소의Binding속성은 SAML 2.0 바인딩 사양(SAMLBind[2])에 지정된 표준 URI다.- HTTP POST 바인딩을 지원하는
<md:AssertionConsumerService>요소의Location속성(index="0")은 "이중 POST" 프로필의 4단계에서 사용된다. - HTTP 아티팩트 바인딩을 지원하는
<md:AssertionConsumerService>요소의Location속성(index="1")은 "이중 아티팩트" 프로필의 6단계에서 사용된다. <md:AttributeConsumingService>요소는 웹 브라우저 SSO와 함께 서비스 공급자에게 푸시되는<saml:AttributeStatement>요소를 구성하기 위해 ID 공급자가 사용한다.<md:AttributeConsumingService>요소의index속성은<samlp:AuthnRequest>요소의AttributeConsumingServiceIndex속성 값으로 사용된다.
이 섹션 시작 부분에 언급된 대로, Location 속성 값은 ID 공급자가 SAML 메시지를 라우팅하는 데 사용되며, 이는 악의적인 서비스 공급자가 중간자 공격을 조직할 가능성을 최소화한다.
메타데이터 집계
이전 예시에서는 각 <md:EntityDescriptor> 요소가 디지털 서명된 것으로 표시된다. 그러나 실제로는 여러 <md:EntityDescriptor> 요소가 전체 집합에 대한 단일 디지털 서명과 함께 <md:EntitiesDescriptor> 요소 아래에 그룹화된다.
<md:EntitiesDescriptor validUntil="2013-03-22T23:00:00Z"
xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<!-- insert ds:Signature element (omitted) -->
<md:EntityDescriptor entityID="https://idp.example.org/SAML2">
...
</md:EntityDescriptor>
<md:EntityDescriptor entityID="https://sp.example.com/SAML2">
...
</md:EntityDescriptor>
</md:EntitiesDescriptor>
위 <md:EntitiesDescriptor> 요소에 대한 다음 세부 사항에 주목하자.
- 디지털 서명(간결성을 위해 생략됨)은 전체 집합을 포함한다.
validUntilXML 속성이 부모 요소로 승격되어 만료 날짜가 각 자식 요소에 적용됨을 의미한다.- XML 네임스페이스 선언이 중복 네임스페이스 선언을 피하기 위해 부모 요소로 승격되었다.
일반적으로 메타데이터 집계는 집계 내의 모든 메타데이터의 무결성을 보증하는 페더레이션이라고 하는 신뢰할 수 있는 제3자에 의해 게시된다. 메타데이터 집계는 매우 클 수 있으며, 집계당 수백 또는 수천 개의 엔터티로 구성될 수 있다는 점에 주목하자.
Remove ads
같이 보기
- SAML
- SAML 1.1
- SAML 메타데이터
- SAML 기반 제품 및 서비스
- OpenID Connect
각주
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads