以编程方式管理 SAML 和 OIDC 提供商

本文档介绍如何使用 Identity Platform Admin SDK 以编程方式管理安全断言标记语言 (SAML) 2.0 和 OpenID Connect (OIDC) 提供商配置。

利用 Admin SDK,您可以自动配置提供商、执行基本 CRUD 操作、轮替证书等。如果您有大量提供商,使用 Cloud Console 手动进行管理会非常繁琐,此时这种做法就会非常有用。

准备工作

使用 SAML 提供商

创建 SAML 提供商配置

创建 SAML 提供商配置时,您需要提供以下参数。如需详细了解如何获取某些值,您可能需要参阅身份提供商的文档。

显示名
配置的易记显示名。此名称也是 Cloud Console 中的提供商标签。
已启用
当前提供商配置是启用还是停用。用户无法通过已停用的提供商登录。
提供方 ID
提供商的唯一标识符,以 saml. 开头。
身份提供商实体 ID
提供商的实体 ID。
SSO 网址
提供商的 SAML SSO 网址。网址必须有效。
X.509 证书

SAML 提供商 X.509 证书的列表,包括 -----BEGIN CERTIFICATE----------END CERTIFICATE---- 字符串。这些证书用于对身份提供商进行令牌签名。

当 Identity Platform 收到 SAML 响应时,将使用记录的证书验证其签名。如果验证失败,响应将被拒绝。密钥轮替时,您需要更新这些证书。请考虑上传多个证书,以防止在轮替期间发生中断。

依赖方实体 ID
SAML 依赖方 (RP/SP) 实体 ID。这通常是应用的网址。SAML 身份提供商称其为受众。
回调网址

身份验证完成后要返回到的网址。SAML 提供商通常将此网址称为断言消费者服务 (ACS) 网址。您需要向 SAML 提供商注册此网址。它的格式为 https://PROJECT-ID.firebaseapp.com/__/auth/handler,类似于 Cloud Console 中显示的网址。如需了解详情,请参阅让用户通过 SAML 登录

使用默认回调网址将降低验证 SAML 响应的复杂程度。但是,您也可以选择显示自定义网域。在这种情况下,请确保为 SAML 身份提供商正确配置了项目的 Identity Platform 回调网址。它的格式通常为 https://AUTH-DOMAIN/__/auth/handler

以下示例展示了如何创建 SAML 提供商配置:

Node.js

const newConfig = {
  displayName: 'SAML provider name',
  enabled: true,
  providerId: 'saml.myProvider',
  idpEntityId: 'IDP_ENTITY_ID',
  ssoURL: 'https://example.com/saml/sso/1234/'
  x509Certificates: [
    '-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----',
    '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
  ],
  rpEntityId: 'RP_ENTITY_ID',
  // Using the default callback URL.
  callbackURL: 'https://project-id.firebaseapp.com/__/auth/handler',
};
admin.auth().createProviderConfig(newConfig).then(() => {
  // Successful creation.
}).catch((error) => {
  // Handle error.
});

Go

newConfig := (&auth.SAMLProviderConfigToCreate{}).
	DisplayName("SAML provider name").
	Enabled(true).
	ID("saml.myProvider").
	IDPEntityID("IDP_ENTITY_ID").
	SSOURL("https://example.com/saml/sso/1234/").
	X509Certificates([]string{
		"-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----",
		"-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----",
	}).
	RPEntityID("RP_ENTITY_ID").
	CallbackURL("https://project-id.firebaseapp.com/__/auth/handler")
saml, err := client.CreateSAMLProviderConfig(ctx, newConfig)
if err != nil {
	log.Fatalf("error creating SAML provider: %v\n", err)
}

log.Printf("Created new SAML provider: %s", saml.ID)

Python

saml = auth.create_saml_provider_config(
    display_name='SAML provider name',
    enabled=True,
    provider_id='saml.myProvider',
    idp_entity_id='IDP_ENTITY_ID',
    sso_url='https://example.com/saml/sso/1234/',
    x509_certificates=[
        '-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----',
        '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
    ],
    rp_entity_id='P_ENTITY_ID',
    callback_url='https://project-id.firebaseapp.com/__/auth/handler')

print('Created new SAML provider:', saml.provider_id)

完成后,该方法会为新建的配置返回 SAMLAuthProviderConfig 对象。

更新 SAML 提供商配置

以下示例展示了如何修改 SAML 提供商配置。您可以更新任何字段,但提供商 ID 除外。

Node.js

const updatedConfig = {
  x509Certificates: [
    '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
    '-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----',
  ],
};
admin.auth().updateProviderConfig('saml.myProvider', updatedConfig).then(() => {
  // Successful update.
}).catch((error) => {
  // Handle error.
});

Go

updatedConfig := (&auth.SAMLProviderConfigToUpdate{}).
	X509Certificates([]string{
		"-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----",
		"-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----",
	})
saml, err := client.UpdateSAMLProviderConfig(ctx, "saml.myProvider", updatedConfig)
if err != nil {
	log.Fatalf("error updating SAML provider: %v\n", err)
}

log.Printf("Updated SAML provider: %s", saml.ID)

Python

saml = auth.update_saml_provider_config(
    'saml.myProvider',
    x509_certificates=[
        '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
        '-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----',
    ])

print('Updated SAML provider:', saml.provider_id)

完成后,该方法会为更新后的配置返回 SAMLAuthProviderConfig 对象。

获取 SAML 提供商配置

标识 SAML 配置的主要方式是使用其提供商 ID。以下示例展示了如何获取 SAML 提供商配置:

Node.js

admin.auth().getProviderConfig('saml.myProvider').then((config) => {
  // Get display name and whether it is enabled.
  console.log(config.displayName, config.enabled);
}).catch((error) => {
  // Handle error. Common error is that config is not found.
});

Go

saml, err := client.SAMLProviderConfig(ctx, "saml.myProvider")
if err != nil {
	log.Fatalf("error retrieving SAML provider: %v\n", err)
}

log.Printf("%s %t", saml.DisplayName, saml.Enabled)

Python

saml = auth.get_saml_provider_config('saml.myProvider')
print(saml.display_name, saml.enabled)

如果存在具有给定 ID 的提供商,则该方法返回 SAMLAuthProviderConfig 对象。

删除 SAML 提供商配置

以下示例展示了如何删除 SAML 提供商配置:

Node.js

admin.auth().deleteProviderConfig('saml.myProvider').then(() => {
  // Successful deletion.
}).catch((error) => {
  // Handle error.
});

Go

if err := client.DeleteSAMLProviderConfig(ctx, "saml.myProvider"); err != nil {
	log.Fatalf("error deleting SAML provider: %v\n", err)
}

Python

auth.delete_saml_provider_config('saml.myProvider')

列出 SAML 提供商配置

以下示例展示了如何列出现有 SAML 提供商配置:

Node.js

// Returns 10 SAML provider configs starting from the specified nextPageToken offset.
admin.auth().listProviderConfigs({type: 'saml', maxResults: 10, pageToken: 'nextPageToken'}).then((results) => {
  results.providerConfigs.forEach((config) => {
    console.log(config.providerId);
  });
  // To list the next 10:
  // return admin.auth().listProviderConfigs(
  //     {type: 'saml', maxResults: 10, pageToken: results.pageToken});
}).catch((error) => {
  // Handle error.
});

Go

iter := client.SAMLProviderConfigs(ctx, "nextPageToken")
for {
	saml, err := iter.Next()
	if err == iterator.Done {
		break
	}
	if err != nil {
		log.Fatalf("error retrieving SAML providers: %v\n", err)
	}

	log.Printf("%s\n", saml.ID)
}

Python

for saml in auth.list_saml_provider_configs('nextPageToken').iterate_all():
    print(saml.provider_id)

每批结果都包含提供商配置列表和用于获取下一批提供商配置的下一页令牌。列出所有提供商后,不会返回任何令牌。

默认情况下,每批返回 100 个提供商。这也是每个批次中的提供商数量上限。

使用 OIDC 提供商

创建 OIDC 提供商配置

创建 OIDC 提供商配置时,您需要提供以下参数。如需详细了解如何获取某些值,您可能需要参阅身份提供商的文档。

显示名
配置的易记显示名。此名称也是 Cloud Console 中的提供商标签。
已启用
当前提供商配置是启用还是停用。用户无法通过已停用的提供商登录。
提供方 ID
提供商的唯一标识符,以 oidc. 开头。
客户端 ID
用于确认 OIDC 提供商 ID 令牌受众的 ID。
客户端密钥
启用 OIDC 代码流所需的客户端密钥。
颁发者
提供商的 Issuer。其格式应类似于 https://example.com。Identity Platform 使用此网址查找 OIDC 发现文档(通常位于 /.well-known/openid-configuration),该文档指定了提供商的 OAuth 端点和公钥。Identity Platform 会根据 OpenID Connect 规范验证 ID 令牌。如果您的提供商不符合用于发现的 OIDC 规范,则不适用于 Identity Platform。
响应类型
OAuth 授权流程的提供商响应类型。您可以将 {idToken, code} 之一设置为 true,但不能同时设置这两者。如果代码流已启用,您必须提供客户端密钥。

以下示例演示了如何创建使用隐式授权流程的 OIDC 提供商配置:

Node.js

const newConfig = {
  displayName: 'OIDC provider name',
  enabled: true,
  clientId: 'CLIENT_ID2',
  issuer: 'https://oidc.com/CLIENT_ID2',
  providerId: 'oidc.provider2',
  responseType: {
    idToken: true,
    code: false,
  },
};
admin.auth().createProviderConfig(newConfig).then(() => {
  // Successful creation.
}).catch((error) => {
  // Handle error.
});

Java

 OidcProviderConfig.CreateRequest request
   = new OidcProviderConfig.CreateRequest()
     .setDisplayName("OIDC provider name")
     .setEnabled(true)
     .setProviderId("oidc.provider2")
     .setClientId("CLIENT_ID2")
     .setIssuer("https://oidc.com/CLIENT_ID2")
     .setIdTokenResponseType(true)
     .setCodeResponseType(false);
 OidcProviderConfig oidc
   = FirebaseAuth.getInstance().createOidcProviderConfig(request);
 System.out.println("Created new OIDC provider: " + oidc.getProviderId());

Go

newConfig := (&auth.OIDCProviderConfigToCreate{}).
	DisplayName("OIDC provider name").
	Enabled(true).
	ID("oidc.myProvider").
	ClientID("CLIENT_ID2").
	Issuer("https://oidc.com/CLIENT_ID2")
oidc, err := client.CreateOIDCProviderConfig(ctx, newConfig)
if err != nil {
	log.Fatalf("error creating OIDC provider: %v\n", err)
}

log.Printf("Created new OIDC provider: %s", oidc.ID)

Python

oidc = auth.create_oidc_provider_config(
    display_name='OIDC provider name',
    enabled=True,
    provider_id='oidc.myProvider',
    client_id='CLIENT_ID2',
    issuer='https://oidc.com/CLIENT_ID2')

print('Created new OIDC provider:', oidc.provider_id)

完成后,该方法会为新建的配置返回 OIDCAuthProviderConfig 对象。

更新 OIDC 提供商配置

以下示例展示了如何修改 OIDC 提供商配置。您可以更新任何字段,但提供商 ID 除外。

Node.js

const updatedConfig = {
  displayName: 'OIDC provider name',
  enabled: true,
  clientId: 'CLIENT_ID',
  clientSecret: 'CLIENT_SECRET'
  issuer: 'https://oidc.com/',
  responseType: {
    code: true,
    idToken: false,
  },
};
admin.auth().updateProviderConfig('oidc.myProvider', updatedConfig).then(() => {
  // Successful update.
}).catch((error) => {
  // Handle error.
});

Java

 OidcProviderConfig.UpdateRequest request
   = new OidcProviderConfig.UpdateRequest("oidc.myProvider")
     .setDisplayName("OIDC provider name")
     .setEnabled(true)
     .setClientId("CLIENT_ID")
     .setClientSecret("CLIENT_SECRET")
     .setIssuer("https://oidc.com/")
     .setCodeResponseType(true);
 OidcProviderConfig oidc
   = FirebaseAuth.getInstance().updateOidcProviderConfig(request);
 System.out.println("Updated OIDC provider: " + oidc.getProviderId());

Go

updatedConfig := (&auth.OIDCProviderConfigToUpdate{}).
	DisplayName("OIDC provider name").
	Enabled(true).
	ClientID("CLIENT_ID").
	Issuer("https://oidc.com")
oidc, err := client.UpdateOIDCProviderConfig(ctx, "oidc.myProvider", updatedConfig)
if err != nil {
	log.Fatalf("error updating OIDC provider: %v\n", err)
}

log.Printf("Updated OIDC provider: %s", oidc.ID)

Python

oidc = auth.update_oidc_provider_config(
    'oidc.myProvider',
    client_id='CLIENT_ID',
    issuer='https://oidc.com')

print('Updated OIDC provider:', oidc.provider_id)

完成后,该方法会为更新后的配置返回 OIDCAuthProviderConfig 对象。

获取 OIDC 提供商配置

标识 OIDC 配置的主要方式是使用其提供商 ID。以下示例展示了如何获取 OIDC 提供商配置:

Node.js

admin.auth().getProviderConfig('oidc.myProvider').then((config) => {
  // Get display name and whether it is enabled.
  console.log(config.displayName, config.enabled);
}).catch((error) => {
  // Handle error. Common error is that config is not found.
});

Go

oidc, err := client.OIDCProviderConfig(ctx, "oidc.myProvider")
if err != nil {
	log.Fatalf("error retrieving OIDC provider: %v\n", err)
}

log.Printf("%s %t", oidc.DisplayName, oidc.Enabled)

Python

oidc = auth.get_oidc_provider_config('oidc.myProvider')

print(oidc.display_name, oidc.enabled)

如果存在具有给定 ID 的提供商,则该方法返回 OIDCAuthProviderConfig 对象。

删除 OIDC 提供商配置

以下示例展示了如何删除 OIDC 提供商配置:

Node.js

admin.auth().deleteProviderConfig('oidc.myProvider').then(() => {
  // Successful deletion.
}).catch((error) => {
  // Handle error.
});

Go

if err := client.DeleteOIDCProviderConfig(ctx, "oidc.myProvider"); err != nil {
	log.Fatalf("error deleting OIDC provider: %v\n", err)
}

Python

auth.delete_oidc_provider_config('oidc.myProvider')

列出 OIDC 提供商配置

以下示例展示了如何列出现有 OIDC 提供商配置:

Node.js

// Returns 10 OIDC provider configs starting from the specified nextPageToken offset.
admin.auth().listProviderConfigs({type: 'oidc', maxResults: 10, pageToken: 'nextPageToken'}).then((results) => {
  results.providerConfigs.forEach((config) => {
    console.log(config.providerId);
  });
  // To list the next 10:
  // return admin.auth().listProviderConfigs(
  //     {type: 'oidc', maxResults: 10, pageToken: results.pageToken});
}).catch((error) => {
  // Handle error.
});

Go

iter := client.OIDCProviderConfigs(ctx, "nextPageToken")
for {
	oidc, err := iter.Next()
	if err == iterator.Done {
		break
	}
	if err != nil {
		log.Fatalf("error retrieving OIDC providers: %v\n", err)
	}

	log.Printf("%s\n", oidc.ID)
}

Python

for oidc in auth.list_oidc_provider_configs('nextPageToken').iterate_all():
    print(oidc.provider_id)

每批结果都包含提供商配置列表和用于获取下一批提供商配置的下一页令牌。列出所有提供商后,不会返回任何令牌。

默认情况下,每批返回 100 个提供商。这也是每个批次中的提供商数量上限。

后续步骤