SAML ์†์„ฑ ์ „ํŒŒ ๊ตฌ์„ฑ

์ด ํŽ˜์ด์ง€์—์„œ๋Š” SAML(๋ณด์•ˆ ๋ณด์žฅ ๋งˆํฌ์—… ์–ธ์–ด) ์†์„ฑ ์ „ํŒŒ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ID ๊ณต๊ธ‰์—…์ฒด์˜ SAML ์†์„ฑ์„ IAP(Identity-Aware Proxy)๋กœ ๋ณดํ˜ธ๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ „ํŒŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. SAML ์†์„ฑ์„ ์ „ํŒŒํ•  ๋•Œ, ์ „ํŒŒํ•  ์†์„ฑ๊ณผ ์ „ํŒŒํ•  ๋ฐฉ๋ฒ•์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

SAML V2.0 ์–ด์„ค์…˜ ๋ฐ ํ”„๋กœํ† ์ฝœ ์‚ฌ์–‘ (PDF)์— ๊ด€ํ•ด ์ž˜ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๊ฐ€ ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฐฉ์‹ ์ดํ•ด

SAML ์†์„ฑ ์ „ํŒŒ๋ฅผ ์‚ฌ์šฉ ์„ค์ •ํ•˜๊ธฐ ์ „์—Google Cloud ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์ด ์ฑ„๋„์„ ํ†ตํ•ด ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜ ์ „๋‹ฌํ•ด์„œ๋Š” ์•ˆ ๋˜๋Š” ์ •๋ณด ์œ ํ˜•์„ ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

IAP๊ฐ€ ๋ณดํ˜ธ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ œ๊ณตํ•˜๋Š” ์ •๋ณด์— ํ•˜๋‚˜ ์ด์ƒ์˜ ์†์„ฑ์„ ํฌํ•จํ•˜๋„๋ก IAP๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋“œ ํŒŒํ‹ฐ ID ๊ณต๊ธ‰์—…์ฒด๋ฅผ ํ†ตํ•ด SSO๋ฅผ ์„ค์ •ํ•˜๊ณ  ID ๊ณต๊ธ‰์—…์ฒด๊ฐ€ SAML ์–ด์„ค์…˜์— <AttributeStatement>๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒฝ์šฐGoogle Cloud ๋Š” ์‚ฌ์šฉ์ž์˜ Google ๊ณ„์ • ์„ธ์…˜์— ์—ฐ๊ฒฐ๋œ ์†์„ฑ์„ ์ž„์‹œ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. Google ๊ณ„์ • ์„ธ์…˜์ด ๋งŒ๋ฃŒ๋˜๋ฉด ๋น„๋™๊ธฐ ํ”„๋กœ์„ธ์Šค๋Š” ์ผ์ฃผ์ผ ๋‚ด์— ์ •๋ณด๋ฅผ ์˜๊ตฌ์ ์œผ๋กœ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. ๋งŒ๋ฃŒ์ผ์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์ • ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด, ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ, ์นด๋“œ ์†Œ์ง€์ž ๋ฐ์ดํ„ฐ, ๊ธˆ์œต ๊ณ„์ • ๋ฐ์ดํ„ฐ, ์˜๋ฃŒ ์ •๋ณด, ๋ฏผ๊ฐํ•œ ๋ฐฐ๊ฒฝ ์ •๋ณด์™€ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ๊ฐœ์ธ ์‹๋ณ„ ์ •๋ณด(PII)์—๋Š” SAML ์†์„ฑ ์ „ํŒŒ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”.

SAML ์†์„ฑ ์ „ํŒŒ ์‚ฌ์šฉ ์„ค์ •

Google Workspace์—์„œ SSO ํ”„๋กœํ•„์„ ๋งŒ๋“ค์–ด SAML ์†์„ฑ ์ „ํŒŒ๋ฅผ ์‚ฌ์šฉ ์„ค์ •ํ•œ ๋‹ค์Œ Google Cloud CLI ๋˜๋Š” REST API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ IAP ์„ค์ •์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

์ฝ˜์†”

  1. Google Cloud Console์—์„œ IAP ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
    IAP๋กœ ์ด๋™
  2. ๋ฆฌ์†Œ์Šค ์„ค์ •์„ ์—ด๊ณ  ์†์„ฑ ์ „ํŒŒ๋กœ ์Šคํฌ๋กคํ•ฉ๋‹ˆ๋‹ค.
  3. ์†์„ฑ ์ „ํŒŒ ์‚ฌ์šฉ ์„ค์ •์„ ์„ ํƒํ•œ ๋‹ค์Œ ์ €์žฅ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  4. SAML ์†์„ฑ ํƒญ์—์„œ ๋‹ค์Œ ํ˜•์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ์ „ํŒŒํ•˜๋ ค๋Š” ์†์„ฑ์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค. attribute1, attribute2, attribute3

    ์ปค์Šคํ…€ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ์†์„ฑ์„ ์ž…๋ ฅํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปค์Šคํ…€ ํ‘œํ˜„์‹์˜ ์†์„ฑ์€ SAML ์†์„ฑ ํƒญ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. SAML ์†์„ฑ ํƒญ์— ์†์„ฑ์ด ํ‘œ์‹œ๋˜๋ ค๋ฉด ๋‹ค์Œ ํ‘œํ˜„ ํ˜•์‹์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    attributes.saml_attributes.filter(attribute, attribute.name in ['attribute', 'attribute2', 'attribute1'])

  5. ์ „๋‹ฌํ•  ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด ์œ ํ˜•์˜ ๊ฒฝ์šฐ IdP์—์„œ ์ˆ˜์‹ ๋˜๋Š” ์†์„ฑ ํ˜•์‹์„ ํ•˜๋‚˜ ์ด์ƒ ์„ ํƒํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

gcloud

๋‹ค์Œ IAP gcloud CLI ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ SAML ์†์„ฑ ์ „ํŒŒ ์„ค์ •์„ ์—…๋ฐ์ดํŠธํ•˜์„ธ์š”.

gcloud iap settings set SETTING_FILE [--folder=FOLDER --organization=ORGANIZATION --project=PROJECT> --resource-type=RESOURCE_TYPE --service=SERVICE --version=VERSION] [GCLOUD_WIDE_FLAG โ€ฆ]

๋‹ค์Œ์„ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

  • FOLDER: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์žˆ๋Š” ํด๋”
  • ORGANIZATION: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์žˆ๋Š” ์กฐ์ง
  • PROJECT: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์žˆ๋Š” ํ”„๋กœ์ ํŠธ
  • RESOURCE_TYPE: ๋ฆฌ์†Œ์Šค ์œ ํ˜•
  • SERVICE: ์„œ๋น„์Šค
  • VERSION: ๋ฒ„์ „ ๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค.

YAML:

applicationSettings:
 attributePropagationSettings:
  expression: CEL_EXPRESSION
  outputCredentials: ARRAY[OUTPUT_CREDENTIALS]
  enable: BOOLEAN

JSON:

{
   "application_settings":{
      "attribute_propagation_settings": {
        "expression": CEL_EXPRESSION,
        "output_credentials": ARRAY[OUTPUT_CREDENTIALS]
        "enable": BOOLEAN
      }
   }
}

REST API

๋‹ค์Œ ์˜ˆ์‹œ์™€ ๊ฐ™์ด IapSettings์—์„œ ApplicationSettings ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ „ํŒŒํ•˜๋„๋ก SAML ์†์„ฑ์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

{
 "csmSettings": {
    object (CsmSettings)
  },
  "accessDeniedPageSettings": {
    object (AccessDeniedPageSettings)
  },
 "attributePropagationSettings": {
    object (AttributePropagationSettings)
  },
  "cookieDomain": string,
}

AttributePropagationSettings

{
 "expression": string,
 "output_credentials": array
 "enable": boolean
}

์ถœ๋ ฅ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด ์„ค์ •

SAML ์†์„ฑ ์ „ํŒŒ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ถœ๋ ฅ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•˜์—ฌ JSON ์›น ํ† ํฐ(JWT) ๋ฐ ํ—ค๋”๋ฅผ ํฌํ•จํ•œ ์—ฌ๋Ÿฌ ๋งค์ฒด์— ์†์„ฑ์„ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. API์—์„œ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•˜๋ ค๋ฉด ๋‹ค์Œ ์˜ˆ์™€ ๊ฐ™์ด ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ๋ฌธ์ž์—ด ๋ชฉ๋ก์„ ์ง€์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

"output_credentials": ["HEADER", "JWT", "RCTOKEN"]

Common Expression Language๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ SAML ์†์„ฑ ํ•„ํ„ฐ๋ง

Common Expression Language(CEL) ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ SAML ์†์„ฑ์„ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SAML ์†์„ฑ ์ „ํŒŒ๋กœ CEL ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•  ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ œํ•œ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํ‘œํ˜„์‹์€ ์†์„ฑ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ‘œํ˜„์‹์—์„œ ์†์„ฑ์„ ์ตœ๋Œ€ 45๊ฐœ๊นŒ์ง€ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ‘œํ˜„์‹ ๋ฌธ์ž์—ด์€ 1,000์ž(์˜๋ฌธ ๊ธฐ์ค€)๋ฅผ ์ดˆ๊ณผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ IAP SAML ์†์„ฑ ์ „ํŒŒ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ๋•Œ ์ง€์›๋˜๋Š” CEL ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋Š” ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜๋ฉฐ ์ž‘์„ฑ๋œ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์—ฐ๊ฒฐํ•  ๋•Œ strict ๋ฐ emitAs ํ•จ์ˆ˜์˜ ์ˆœ์„œ๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ์˜ˆ ์„ค๋ช…
ํ•„๋“œ ์„ ํƒ a.b proto a์—์„œ ํ•„๋“œ b๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. b ๋ฌธ์ž๋Š” ๋‹ค๋ฅธ proto, ๋ชฉ๋ก ์•„๋‹ˆ๋ฉด ๋ฌธ์ž์—ด๊ณผ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ๊ฐ’ ์œ ํ˜•์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ชฉ๋ก ํ•„ํ„ฐ๋ง list.Filter(iter_var, condition) ํ•ญ๋ชฉ์ด condition์„ ์ถฉ์กฑํ•˜๋Š” list ํ•˜์œ„ ์ง‘ํ•ฉ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
๋ชฉ๋ก ๋ฉค๋ฒ„์‹ญ b์— ๋Œ€ํ•ด a a ๊ฐ’์ด b ๋ชฉ๋ก์˜ ๊ตฌ์„ฑ์›์ธ ๊ฒฝ์šฐ true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
selectByName list.selectByName("name") ๋ชฉ๋ก์—์„œ name = "name"์ธ ์†์„ฑ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
append list.append(attribute) ์ง€์ •๋œ ์†์„ฑ์„ ์ง€์ •๋œ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
strict attribute.strict() HEADERS๋ฅผ ์ถœ๋ ฅ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ x-goog-iap-attr- ํ”„๋ฆฌํ”ฝ์Šค ์—†์ด ์†์„ฑ์„ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค.
emitAs attribute.emitAs("new_name") ์ด๋ฆ„์ด "new_name"์ธ ์ง€์ •๋œ ์†์„ฑ์„ ์„ ํƒํ•œ ๋ชจ๋“  ์ถœ๋ ฅ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด์— ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

CEL ํ‘œํ˜„์‹ ์˜ˆ์‹œ

SAML ์–ด์„ค์…˜์„ ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

<saml2:AttributeStatement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <saml2:Attribute Name="my_saml_attr_1">
    <saml2:AttributeValue xsi:type="xsd:string">value_1</saml2:AttributeValue>
    <saml2:AttributeValue xsi:type="xsd:string">value_2</saml2:AttributeValue>
  </saml2:Attribute>
 <saml2:Attribute Name="my_saml_attr_2">
    <saml2:AttributeValue xsi:type="xsd:string">value_3</saml2:AttributeValue>
    <saml2:AttributeValue xsi:type="xsd:string">value_4</saml2:AttributeValue>
  </saml2:Attribute>
 <saml2:Attribute Name="my_saml_attr_3">
    <saml2:AttributeValue xsi:type="xsd:string">value_5</saml2:AttributeValue>
    <saml2:AttributeValue xsi:type="xsd:string">value_6</saml2:AttributeValue>
  </saml2:Attribute>
</saml2:AttributeStatement>

my_saml_attr_1์„ ์„ ํƒํ•˜๋ ค๋ฉด ๋‹ค์Œ CEL ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

attributes.saml_attributes.filter(attribute, attribute.name in ["my_saml_attr_1"])

my_saml_attr_1 ๋ฐ my_saml_attr_2๋ฅผ ์„ ํƒํ•˜๋ ค๋ฉด ๋‹ค์Œ CEL ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

attributes.saml_attributes.filter(attribute, attribute.name in ["my_saml_attr_1", "my_saml_attr_2"])

์†์„ฑ ํ˜•์‹

์„ ํƒํ•œ ๋ชจ๋“  ์†์„ฑ์ด ์„ ํƒํ•œ ๋ชจ๋“  ์ถœ๋ ฅ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด์— ์™„์ „ํžˆ ๋ณต์ œ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ: SAML ์–ด์„ค์…˜ ๊ฐ€์ •

<saml2:AttributeStatement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <saml2:Attribute Name="my_saml_attr_1">
    <saml2:AttributeValue xsi:type="xsd:string">value_1</saml2:AttributeValue>
    <saml2:AttributeValue xsi:type="xsd:string">value_2</saml2:AttributeValue>
  </saml2:Attribute>
</saml2:AttributeStatement>

JWT ๋ฐ RC ํ† ํฐ

JWT ํ† ํฐ์€ additional_claims ํ•„๋“œ๋ฅผ ํ†ตํ•ด ์†์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํ•„๋“œ๋Š” ๊ฐ์ฒด์ด๋ฉฐ ์†์„ฑ ๊ฐ’ ๋ชฉ๋ก์— ๋Œ€ํ•œ ์†์„ฑ ์ด๋ฆ„ ๋งคํ•‘์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์†์„ฑ ์ด๋ฆ„์€ ์ œ๊ณต๋œ SAML ์–ด์„ค์…˜์—์„œ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ SAML ์–ด์„ค์…˜์˜ ๊ฒฝ์šฐ IAP JWT์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

{
  "additional_claims": {
    "my_saml_attr_1": ["value_1", "value_2"]
  }
}

SAML ์–ด์„ค์…˜์˜ ํ—ค๋”

ํ—ค๋”์—์„œ ์†์„ฑ, ํ‚ค, ์ด๋ฆ„ ๊ฐ’์€ RFC 3986์— ๋”ฐ๋ผ URL ์ด์Šค์ผ€์ดํ”„ ์ฒ˜๋ฆฌ๋˜๋ฉฐ ์‰ผํ‘œ๋กœ ์กฐ์ธ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด header&name: header$value๋Š” x-goog-iap-attr-header%26name: header%24value๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

IAP ํ—ค๋”๋ฅผ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ ํ—ค๋”์—๋Š” IAP ํ”„๋ฆฌํ”ฝ์Šค x-goog-iap-attr-์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ๋ถ€ํ•˜ ๋ถ„์‚ฐ๊ธฐ๋Š” x-goog-iap-attr ํ”„๋ฆฌํ”ฝ์Šค๊ฐ€ ์žˆ๋Š” ๋ชจ๋“  ์š”์ฒญ ํ—ค๋”๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์•ฑ์—์„œ ์ˆ˜์‹ ํ•œ ํ—ค๋”๊ฐ€ IAP์—์„œ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ SAML ์–ด์„ค์…˜์˜ ํ—ค๋”๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

"x-goog-iap-attr-my_saml_attr_1": "value_1,value_2"

๋‹ค์Œ ์˜ˆ์‹œ์—์„œ๋Š” value&1, value$2, value,3๊ณผ ๊ฐ™์€ ํ—ค๋”์—์„œ ์†์„ฑ์„ ์ „ํŒŒํ•  ๋•Œ IAP๊ฐ€ ํŠน์ˆ˜ ๋ฌธ์ž๋ฅผ ์ด์Šค์ผ€์ดํ”„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

"x-goog-iap-attr-my_saml_attr_1": "value%261,value%242,value%2C3"

๋‹ค์Œ์€ ํ—ค๋” ์ด๋ฆ„์ด ์ด์Šค์ผ€์ดํ”„๋˜๋Š” ๋ฐฉ๋ฒ•์˜ ์˜ˆ์ž…๋‹ˆ๋‹ค.

ํ—ค๋” ์ด๋ฆ„:

"iap,test,3": "iap_test3_value1,iap_test3_value2"

์ด์Šค์ผ€์ดํ”„ ์ฒ˜๋ฆฌ๋œ ํ—ค๋” ์ด๋ฆ„:

"X-Goog-IAP-Attr-iap%2Ctest%2C3": "iap_test3_value1,iap_test3_value2"

์†์„ฑ ๋งž์ถค์„ค์ •

selectByName, append, strict, emitas ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ „ํŒŒ๋œ ์†์„ฑ ์ด๋ฆ„์„ ์ˆ˜์ •ํ•˜๊ณ  ์ผ๋ถ€ ์†์„ฑ์— ํ—ค๋” ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์‚ฌ์šฉํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์ง€์ •ํ•œ ํ›„ ์ƒˆ IAP ์ œ๊ณต ์†์„ฑ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SAML ์†์„ฑ ์ „ํŒŒ๋Š” ํ•„์š” ์—†์ง€๋งŒ SM_USER ํ•„๋“œ์— ์ด๋ฉ”์ผ ์ฃผ์†Œ, ๊ธฐ๊ธฐ ID ๋˜๋Š” ํƒ€์ž„์Šคํƒฌํ”„๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ iap_attributes list: attributes.iap_attributesโ€ฆ์—์„œ ์ด๋Ÿฌํ•œ ์†์„ฑ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

IAP๋Š” user_email, device_id, timestamp ์†์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ

๋‹ค์Œ ์˜ˆ์‹œ์—์„œ๋Š” selectByName, append, strict, emitas ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†์„ฑ์„ ๋งž์ถค์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์˜ˆ์‹œ SAML ์–ด์„ค์…˜์„ ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

selectByName

selectByName ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฃผ์–ด์ง„ ๋ชฉ๋ก์—์„œ ์ด๋ฆ„๋ณ„๋กœ ๋‹จ์ผ ์†์„ฑ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด my_saml_attr_1์„ ์„ ํƒํ•˜๋ ค๋ฉด ๋‹ค์Œ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

attributes.saml_attributes.selectByName("my_saml_attr_1")

append

append ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†์„ฑ ๋ชฉ๋ก์— ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ง€์›๋˜๋Š” IAP ์†์„ฑ ๋ชฉ๋ก ์ค‘ ํ•˜๋‚˜์—์„œ ์ด ์†์„ฑ์„ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด my_saml_attr_1์ด ํฌํ•จ๋œ ๋ชฉ๋ก์— my_saml_attr_2๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋‹ค์Œ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

attributes.saml_attributes.filter(x, x.name in ["my_saml_attr_1"]).append(attributes.saml_attributes.selectByName("my_saml_attr_2"))

"my_saml_attr_2"๋ฅผ ํ•„ํ„ฐ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—ฐ๊ฒฐ์„ ์—ฐ๊ฒฐํ•˜์—ฌ ์†์„ฑ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

attributes.saml_attributes.filter(x, x.name in ["my_saml_attr_1"]).append(
attributes.saml_attributes.selectByName("my_saml_attr_2")).append(
attributes.saml_attributes.selectByName("my_saml_attr_3"))

๋‹จ์ผ ์†์„ฑ ์ถ”๊ฐ€๋Š” strict ๋ฐ emitAs ๊ธฐ๋Šฅ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ€์žฅ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

strict

IAP์—์„œ x-goog-iap-attr- ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์ด๋ฆ„์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋„๋ก strict ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†์„ฑ์— ํ”Œ๋ž˜๊ทธ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์†์„ฑ ์ด๋ฆ„์ด ์ •ํ™•ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

attributes.saml_attributes.selectByName("my_saml_attr_1").strict()

emitAs

emitAs ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†์„ฑ์˜ ์ƒˆ ์ด๋ฆ„์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ง€์ •ํ•œ ์ด๋ฆ„์ด ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด์— ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด my_saml_attr_1์„ custom_name์œผ๋กœ ๋ฐ”๊พธ๋ ค๋ฉด ๋‹ค์Œ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

attributes.saml_attributes.selectByName("my_saml_attr_1").emitAs("custom_name")

๋‹ค์–‘ํ•œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋งž๊ฒŒ ์†์„ฑ์„ ๋งž์ถค์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜์—ฌ IAP ์†์„ฑ์—์„œ ๋‹ค๋ฅธ SAML ์†์„ฑ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ์„ "SM_USER"๋กœ ์ „ํŒŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

attributes.saml_attributes.filter(x, x.name in ["my_saml_attr_1"]).append(
attributes.iap_attributes.selectByName("user_email").emitAs("SM_USER").strict())

์ถœ๋ ฅ ํ—ค๋”๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

"x-goog-iap-attr-my_saml_attr_1": "value_1,value_2"
"SM_USER": "email@domain.com"

SAML ์†์„ฑ ์ „ํŒŒ ์‚ฌ์šฉ ์‹œ ์ œ์•ฝ์กฐ๊ฑด

๋กœ๊ทธ์ธ ์‹œ, ID ๊ณต๊ธ‰์—…์ฒด์—์„œ ๋“ค์–ด์˜ค๋Š” ์†์„ฑ์˜ SAML ์†์„ฑ ๋ฐ์ดํ„ฐ๋Š” 2KB๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. 2KB ํ•œ๋„๋ฅผ ์ดˆ๊ณผํ•˜๋Š” ์–ด์„ค์…˜์€ ๊ฑฐ๋ถ€๋˜๊ณ  ๋กœ๊ทธ์ธ์— ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ์›น ์„œ๋ฒ„๋Š” ์š”์ฒญ ํฌ๊ธฐ ํ•œ๋„๊ฐ€ 8KB์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ—ค๋”์˜ ์ค‘๋ณต ์†์„ฑ์„ ๋น„๋กฏํ•˜์—ฌ ๋ฐœ์‹  ์ปค์Šคํ…€ ์†์„ฑ์˜ ํฌ๊ธฐ๊ฐ€ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฆ„์— ๊ฐ’์ด ์ถ”๊ฐ€๋œ ์†์„ฑ์ด ๋ณต์ œ ๋ฐ ์ธ์ฝ”๋”ฉ๋˜์—ˆ์„ ๋•Œ ํฌ๊ธฐ๊ฐ€ 5,000๋ฐ”์ดํŠธ๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด IAP๊ฐ€ ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•˜๊ณ  IAP ์˜ค๋ฅ˜ ์ฝ”๋“œ 401์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

SAML ์†์„ฑ ์ „ํŒŒ์˜ ์œ ๋‹ˆ์ฝ”๋“œ ๋ฌธ์ž

์ด ๊ธฐ๋Šฅ์€ ์œ ๋‹ˆ์ฝ”๋“œ ๋ฐ UTF-8 ๋ฌธ์ž๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์†์„ฑ ๊ฐ’์€ ํ•˜์œ„ ASCII ๋ฌธ์ž์—ด์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด์„ค์…˜์ด ํ•˜์œ„ ASCII๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ๋กœ๊ทธ์ธ์— ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.