SAML 속성
SAML 속성 (AttributeStatement)
SAML 어써션이 "인증했는지"만 알려준다면, **속성 문장(AttributeStatement)**은 "그 사용자가 어떤 사람인지"를 구체적으로 알려줘요. 이메일, 그룹 멤버십, 부서 같은 정보를 <Attribute> 요소에 담아서 서비스에 전달하고, 서비스는 이 속성으로 사용자를 식별하거나 권한을 부여하지요. 이번에는 속성 문장과 <Attribute> 요소의 스키마, 그리고 속성 이름을 구분하는 형식까지 살펴볼게요.
출처: SAML V2.0 Assertion Schema (saml-schema-assertion-2.0.xsd)
본문
<AttributeStatement>의 구조
속성 문장은 StatementAbstractType에서 파생되고, 그 안에 <Attribute> 또는 암호화된 <EncryptedAttribute>를 몇 개든 담을 수 있어요.
<element name="AttributeStatement" type="saml:AttributeStatementType"/>
<complexType name="AttributeStatementType">
<complexContent>
<extension base="saml:StatementAbstractType">
<choice maxOccurs="unbounded">
<element ref="saml:Attribute"/>
<element ref="saml:EncryptedAttribute"/>
</choice>
</extension>
</complexContent>
</complexType>
<Attribute> 요소
각 속성은 이름(Name)으로 식별돼요. 이름을 어떻게 해석할지는 NameFormat이 정하고, 사람이 읽기 쉬운 별칭은 FriendlyName으로 줄 수 있어요. 실제 값은 <AttributeValue>에 담겨요.
<element name="Attribute" type="saml:AttributeType"/>
<complexType name="AttributeType">
<sequence>
<element ref="saml:AttributeValue" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="Name" type="string" use="required"/>
<attribute name="NameFormat" type="anyURI" use="optional"/>
<attribute name="FriendlyName" type="string" use="optional"/>
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
<AttributeValue>는 anyType이라서 문자열뿐 아니라 구조화된 값도 담을 수 있어요.
<element name="AttributeValue" type="anyType" nillable="true"/>
속성 이름 형식 (NameFormat)
이름을 어떻게 이해해야 할지를 나타내는 값이 NameFormat이에요. SAML이 정리해 둔 대표적인 형식은 아래 같아요.
urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified—NameFormat을 명시하지 않으면 적용되는 기본값이에요. 이름이 어떻게 해석될지 정해지지 않았다는 뜻이에요.urn:oasis:names:tc:SAML:2.0:attrname-format:uri— 이름이 URI 참조로 해석돼요. 유일성 있게 속성을 식별하기 좋아요.urn:oasis:names:tc:SAML:2.0:attrname-format:basic— SAML 1.x 시절의 속성 이름 형식이에요.
이 URI 값들은 엔드포인트나 프로토콜 요소와 마찬가지로 문자 그대로 보존해야 할 식별자예요. 실무에서 IdP가 어떤 NameFormat을 쓰는지에 따라 SP 쪽 속성 매핑이 달라지니까 꼭 확인하는 게 좋아요.
메타데이터에서 속성 요청하기
SP는 메타데이터의 **<AttributeConsumingService>**에 <RequestedAttribute>를 두고, 어느 속성이 필요한지 미리 알릴 수 있어요. isRequired="true"면 그 속성이 없을 때 서비스가 동작하지 않는다는 뜻이에요.
<complexType name="RequestedAttributeType">
<complexContent>
<extension base="saml:AttributeType">
<attribute name="isRequired" type="boolean" use="optional"/>
</extension>
</complexContent>
</complexType>
이렇게 SP가 "나는 이 속성들이 필요해요"라고 선언해 두면, IdP는 그에 맞춰 어써션에 속성 문장을 채워서 보내기 쉬워져요.
실제 어써션에서의 모습 (요약)
어써션 하나에 인증 문장과 속성 문장이 함께 실리는 경우가 흔해요. 속성 문장 부분만 떼어 보면 대략 이런 모양이지요.
<AttributeStatement>
<Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<AttributeValue>[email protected]</AttributeValue>
</Attribute>
</AttributeStatement>
값을 주고받을 때 문자열 비교는 대소문자 무시나 공백 정규화에 의존하지 말고, 스키마가 정의한 대로 처리해야 해요.
더 알아보기
- SAML 어써션 — 속성 문장이 속해 있는
<Assertion>의 구조. - SAML 메타데이터 — SP가 필요한 속성을 선언하는
AttributeConsumingService. - SAML 브라우저 SSO 플로 — 속성 문장이 담긴
<Response>가 오가는 흐름.