通过代码 WSO2 身份服务器配置服务提供者

Configure a service provider via code WSO2 Identity Server

我正在尝试配置我的 WSO2 身份服务器以通过 .xml 文件设置服务提供商。以下是我正在采取的步骤:

  1. 将服务提供商 .xml 文件粘贴到 $WSO2_HOME/repository/conf/identity/service-providers 文件夹中
  2. 运行 全新 WSO2 环境中的 wso2server.sh 脚本(从不设置,带有空表的数据库)

我在步骤 1 中创建的 .xml 文件是使用控制台的 "export" 功能创建的,因此我非常有信心它已正确设置。为了以防万一,这是代码(出于隐私考虑删除了带有“REMOVED”的行):

<?xml version="1.0" encoding="UTF-8"?><ServiceProvider>
  <ApplicationName>__REMOVED__</ApplicationName>
  <Description>__REMOVED__</Description>
  <InboundAuthenticationConfig>
    <InboundAuthenticationRequestConfigs>
      <InboundAuthenticationRequestConfig>
        <InboundAuthKey>__REMOVED__</InboundAuthKey>
        <InboundAuthType>passivests</InboundAuthType>
        <InboundConfigType>standardAPP</InboundConfigType>
        <Properties/>
      </InboundAuthenticationRequestConfig>
      <InboundAuthenticationRequestConfig>
        <InboundAuthKey>__REMOVED__</InboundAuthKey>
        <InboundAuthType>openid</InboundAuthType>
        <InboundConfigType>standardAPP</InboundConfigType>
        <Properties/>
      </InboundAuthenticationRequestConfig>
      <InboundAuthenticationRequestConfig>
        <InboundAuthKey>__REMOVED__</InboundAuthKey>
        <InboundAuthType>oauth2</InboundAuthType>
        <InboundConfigType>standardAPP</InboundConfigType>
        <inboundConfiguration><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<oAuthAppDO>
    <oauthConsumerKey>__REMOVED__</oauthConsumerKey>
    <oauthConsumerSecret>__REMOVED__</oauthConsumerSecret>
    <applicationName>__REMOVED__</applicationName>
    <callbackUrl></callbackUrl>
    <oauthVersion>OAuth-2.0</oauthVersion>
    <grantTypes>client_credentials </grantTypes>
    <scopeValidators/>
    <pkceSupportPlain>true</pkceSupportPlain>
    <pkceMandatory>false</pkceMandatory>
    <userAccessTokenExpiryTime>3600</userAccessTokenExpiryTime>
    <applicationAccessTokenExpiryTime>3600</applicationAccessTokenExpiryTime>
    <refreshTokenExpiryTime>84600</refreshTokenExpiryTime>
    <idTokenExpiryTime>3600</idTokenExpiryTime>
    <audiences/>
    <bypassClientCredentials>false</bypassClientCredentials>
    <requestObjectSignatureValidationEnabled>false</requestObjectSignatureValidationEnabled>
    <idTokenEncryptionEnabled>false</idTokenEncryptionEnabled>
    <idTokenEncryptionAlgorithm>null</idTokenEncryptionAlgorithm>
    <idTokenEncryptionMethod>null</idTokenEncryptionMethod>
    <backChannelLogoutUrl></backChannelLogoutUrl>
    <tokenType>JWT</tokenType>
</oAuthAppDO>
]]></inboundConfiguration>
        <Properties/>
      </InboundAuthenticationRequestConfig>
    </InboundAuthenticationRequestConfigs>
  </InboundAuthenticationConfig>
  <LocalAndOutBoundAuthenticationConfig>
    <AuthenticationSteps/>
    <AuthenticationType>default</AuthenticationType>
    <alwaysSendBackAuthenticatedListOfIdPs>false</alwaysSendBackAuthenticatedListOfIdPs>
    <UseTenantDomainInUsername>false</UseTenantDomainInUsername>
    <UseUserstoreDomainInRoles>true</UseUserstoreDomainInRoles>
    <UseUserstoreDomainInUsername>false</UseUserstoreDomainInUsername>
    <EnableAuthorization>false</EnableAuthorization>
  </LocalAndOutBoundAuthenticationConfig>
  <RequestPathAuthenticatorConfigs/>
  <InboundProvisioningConfig>
    <ProvisioningUserStore/>
    <IsProvisioningEnabled>false</IsProvisioningEnabled>
    <IsDumbModeEnabled>false</IsDumbModeEnabled>
  </InboundProvisioningConfig>
  <OutboundProvisioningConfig>
    <ProvisioningIdentityProviders/>
  </OutboundProvisioningConfig>
  <ClaimConfig>
    <RoleClaimURI/>
    <LocalClaimDialect>false</LocalClaimDialect>
    <IdpClaim/>
    <ClaimMappings>
      <ClaimMapping>
        <LocalClaim>
          <ClaimUri>http://wso2.org/claims/role</ClaimUri>
          <claimId>0</claimId>
        </LocalClaim>
        <RemoteClaim>
          <ClaimUri>roles</ClaimUri>
          <claimId>0</claimId>
        </RemoteClaim>
        <RequestClaim>true</RequestClaim>
        <MandatoryClaim>false</MandatoryClaim>
      </ClaimMapping>
    </ClaimMappings>
    <AlwaysSendMappedLocalSubjectId>false</AlwaysSendMappedLocalSubjectId>
    <SPClaimDialects/>
  </ClaimConfig>
  <PermissionAndRoleConfig>
    <Permissions/>
    <RoleMappings/>
    <IdpRoles/>
  </PermissionAndRoleConfig>
  <IsSaaSApp>false</IsSaaSApp>
</ServiceProvider>

启动脚本完成后,我在控制台中没有看到服务提供商:

我注意到了一些奇怪的事情 - 如果我尝试使用控制台手动导入服务提供者,我会在 UI 读数上收到错误消息:

Error in importing provided service provider serviceprovider@carbon.super from file

我的控制台输出显示:

Caused by: org.wso2.carbon.identity.application.common.IdentityApplicationManagementException: Application with the same name loaded from the file system.
        at org.wso2.carbon.identity.application.mgt.ApplicationManagementServiceImpl.doAddApplication(ApplicationManagementServiceImpl.java:1637)
        at org.wso2.carbon.identity.application.mgt.ApplicationManagementServiceImpl.createApplicationWithTemplate(ApplicationManagementServiceImpl.java:169)
        at org.wso2.carbon.identity.application.mgt.ApplicationManagementServiceImpl.importSPApplicationFromObject(ApplicationManagementServiceImpl.java:1025)
        ... 80 more

我找到了这个错误的源代码,它是 ApplicationManagementServiceImpl.java 文件

if (ApplicationManagementServiceComponent.getFileBasedSPs().containsKey(applicationName)) {
    throw new IdentityApplicationManagementException(
            "Application with the same name loaded from the file system.");
}

调用 ApplicationManagementServiceComponent.java

private void buildFileBasedSPList() {
        String spConfigDirPath = CarbonUtils.getCarbonConfigDirPath() + File.separator + "identity"
                + File.separator + "service-providers";
        FileInputStream fileInputStream = null;
        File spConfigDir = new File(spConfigDirPath);
        OMElement documentElement;

        if (spConfigDir.exists()) {

            for (final File fileEntry : spConfigDir.listFiles()) {
                try {
                    if (!fileEntry.isDirectory()) {
                        fileInputStream = new FileInputStream(new File(fileEntry.getAbsolutePath()));
                        documentElement = new StAXOMBuilder(fileInputStream).getDocumentElement();
                        ServiceProvider sp = ServiceProvider.build(documentElement);
                        if (sp != null) {
                            fileBasedSPs.put(sp.getApplicationName(), sp);
                        }
                    }
                } catch (Exception e) {
                    log.error("Error while loading idp from file system.", e);
                } finally {
                    if (fileInputStream != null) {
                        try {
                            fileInputStream.close();
                        } catch (IOException e) {
                            log.error("Error occurred while closing file input stream for file " + spConfigDirPath, e);
                        }
                    }

抛出错误是因为我的服务提供商目录中有一个具有相同服务提供商名称的文件正试图通过控制台导入。但是,我的文件系统中的服务提供者并没有首先导入。

因此,我在配置服务器时未能导入服务提供商,这使我无法稍后通过控制台导入文件。

感谢任何帮助。

作为文件 $WSO2_HOME/repository/conf/identity/service-providers 文件夹部署的服务提供商将不会在 UI 中可见。但它将在系统中处于活动状态。目前不支持部署文件中的InboundAuthenticationConfig。但是,您可以在 $WSO2_HOME/repository/conf/identity/sso-idp-config.xml 文件中拥有 SAML 配置。

<SSOIdentityProviderConfig>
  <ServiceProviders>
    .......
    .......
    <ServiceProvider>
       <Issuer>_InboundAuthKey_</Issuer>
       <AssertionConsumerServiceURLs>
           <AssertionConsumerServiceURL>_url_</AssertionConsumerServiceURL>
       </AssertionConsumerServiceURLs>
      ......
       ......
   </ServiceProvider>
  </ServiceProviders>
</SSOIdentityProviderConfig>

这里的 InboundAuthKey 是 saml InboundAuthenticationRequestConfig

的值

我未能通过将文件存储到 $WSO2_HOME/repository/conf/identity/service-providers 来设置服务提供商。 OAuth2/token 请求总是失败,错误是找不到特定的 client_id。

对我有用的是创建 python 脚本以使用 SOAP 接口加载 XML。

import zeep
from requests import Session
import os

session = Session()
#uncomment in case you use HTTPS without valid certificates
session.verify = False
transport = zeep.Transport(session=session)


def get_client(service):
    base_url = 'https://{IS_SERVICE_NAME}:{IS_PORT}/services/{SERVICE}?wsdl'.format(
        IS_SERVICE_NAME=os.environ["IS_SERVICE_NAME"],
        IS_PORT=os.environ["IS_PORT"],
        SERVICE=service)
    print("Getting client %s" % base_url)
    return zeep.Client(base_url, transport=transport)


def init_session():
    client = get_client('AuthenticationAdmin')

    client.service.login(username=os.environ["IS_USERNAME"],
                         password=os.environ["IS_PASSWORD"],
                         remoteAddress=os.environ["IS_SERVICE_NAME"])


def import_config(path):
    print("Calling IdentityApplicationManagementService")
    client_iam = get_client('IdentityApplicationManagementService')

    with open(path) as f:
        contents = f.read()

    # list of available namespaces
    # print client_iam.client_iam.namespaces
    sp_file_content_type = client_iam.get_type('ns2:SpFileContent')
    sp_file_content = sp_file_content_type(content=contents,
                                           fileName='service-provider.xml')
    client_iam.service.importApplication(sp_file_content)


if __name__ == '__main__':
    assert "IS_USERNAME" in os.environ, "Define IS_USERNAME env variable"
    assert "IS_PASSWORD" in os.environ, "Define IS_PASSWORD env variable"
    assert "IS_SERVICE_NAME" in os.environ, "Define IS_SERVICE_NAME env variable"
    assert "IS_PORT" in os.environ, "Define IS_PORT env variable"

    init_session()
    import_config('/conf/service-provider.xml')

此 SOAP 接口已通过 carbon.xml 中的设置启用。

<HideAdminServiceWSDLs>false</HideAdminServiceWSDLs>