Yur*_*kov 8 java oauth-2.0 openid-connect keycloak idp
我正在使用身份代理功能和外部 IDP。因此,用户登录到外部 IDP UI,然后 KeyCloak 代理客户端从外部 IDP 接收 JWT 令牌,KeyCloak 提供 JWT,我们可以使用它来访问资源。我已经设置了Default Identitiy Provider功能,因此外部 IDP 登录屏幕会在用户登录时显示给用户。这意味着用户及其密码存储在外部 IDP 上。
当我需要在测试中以编程方式使用“直接访问授权”(资源所有者密码授权)登录时,就会出现问题。由于密码未存储在 KeyCloak 上,我总是在登录时从 KeyCloak 收到 401 Unauthorized 错误。当我尝试更改用户密码时,它开始工作,所以问题是 KeyCloak 上没有提供用户密码,并且使用“直接访问授权”KeyCloak 不会在程序登录时调用外部 IDP。
我使用以下代码获取访问令牌,但每次传递有效的用户名/密码时都会出现 401 错误。
org.keycloak.authorization.client.util.HttpResponseException: Unexpected response from server: 401 / Unauthorized
Run Code Online (Sandbox Code Playgroud)
为该客户端启用了直接访问授权。
public static String login(final Configuration configuration) {
final AuthzClient authzClient = AuthzClient.create(configuration);
final AccessTokenResponse accessTokenResponse = authzClient.obtainAccessToken(USERNAME, PASSWORD);
return accessTokenResponse.getToken();
}
Run Code Online (Sandbox Code Playgroud)
有什么办法可以修复吗?例如,在“直接访问授权”上调用身份代理,以便 KeyCloak 向我们提供它的有效令牌?
问题是 KeyCloak 没有来自初始身份提供商的密码信息。它们具有令牌交换功能,应用于程序化令牌交换。
应该使用外部令牌到内部令牌交换来实现它。
下面是 Python 中的示例代码,它可以实现这一点(只需将正确的值放在占位符中):
def login():
idp_access_token = idp_login()
return keycloak_token_exchange(idp_access_token)
def idp_login():
login_data = {
"client_id": <IDP-CLIENT-ID>,
"client_secret": <IDP-CLIENT-SECRET>,
"grant_type": <IDP-PASSWORD-GRANT-TYPE>,
"username": <USERNAME>,
"password": <PASSWORD>,
"scope": "openid",
"realm": "Username-Password-Authentication"
}
login_headers = {
"Content-Type": "application/json"
}
token_response = requests.post(<IDP-URL>, headers=login_headers, data=json.dumps(login_data))
return parse_response(token_response)['access_token']
def keycloak_token_exchange(idp_access_token):
token_exchange_url = <KEYCLOAK-SERVER-URL> + '/realms/master/protocol/openid-connect/token'
data = {
'grant_type': 'urn:ietf:params:oauth:grant-type:token-exchange',
'subject_token': idp_access_token,
'subject_issuer': <IDP-PROVIDER-ALIAS>,
'subject_token_type': 'urn:ietf:params:oauth:token-type:access_token',
'audience': <KEYCLOAK-CLIENT-ID>
}
response = requests.post(token_exchange_url, data=data,
auth=(<KEYCLOAK-CLIENT-ID>, <KEYCLOAK-CLIENT-SECRET>))
logger.info(response)
return parse_response(response)['access_token']
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4952 次 |
| 最近记录: |