我正试图使用Java的RestAssured API来验证进入OKTA的身份。问题的认证类型是多因素的,虽然我在Google Chrome浏览器中总是能够让这种认证成功,但在RestAssured中,尽管匹配了所有的请求头和cookie,却始终以403失败。我的最终目标是获得不记名认证令牌,以便能够在登录后运行服务。
基本上,这是我调用的服务顺序。
1) [redacted]apiv1authn; 我提供我的用户名和密码,以及一些字母数字状态令牌。(我使用了一个围绕RestAssured的RequestSpecification的包装器类:)这将以200成功返回。
// Create a brand new request to login using OKTA.
RequestWrapper requestWrapper11 = new RequestWrapper();
requestWrapper11.setResponseContentType(ContentType.JSON);
requestWrapper11.setAcceptedContentType(ContentType.JSON);
requestWrapper11.setHTTPMethod(Method.POST);
requestWrapper11.setRequestPayload(new HashMap<>() {
{
put("username", "[redacted]");
put("password", "[redacted]");
put("options", new HashMap<String, Object>() {
{ put("warnBeforePasswordExpired", true); }
{ put("multiOptionalFactorEnroll", true); }
});
}
});
// Authenticate and get a brand new state token.
requestWrapper11.setBaseURL(new URL("[redacted]/api/v1/authn"));
ResponseWrapper response = requestWrapper11.executeAndGetResponse();
从这个服务调用中,我得到了一个状态令牌,我在下一步使用,以及一个因子ID。
2)然后我调用POST服务[redacted]apiv1authnfactors,并提供安全问题的答案。(这也会成功返回200):
{answer: "[redacted_1]",stateToken:"[state_token]"}。
RequestWrapper requestWrapper2 = new RequestWrapper();
requestWrapper2.setResponseContentType(ContentType.JSON);
requestWrapper2.setAcceptedContentType(ContentType.JSON);
requestWrapper2.setHTTPMethod(Method.POST);
requestWrapper2.setRequestPayload(new HashMap<>() {
{
put("answer", "[redacted]");
put("stateToken", stateToken);
}
});
requestWrapper2.setOverrideQueryParams(new HashMap<>() {
{ put("rememberDevice", false); }
});
// Authenticate and get a brand new state token.
requestWrapper2.setBaseURL(new URL("[redacted]/api/v1/authn/factors/" + factorId + "/verify"));
3)最后,我做了一个GET调用[redacted]loginstep-upredirect?stateToken=[state_token]来返回一个用于认证的特殊代码。
RequestWrapper requestWrapper4 = new RequestWrapper();
// requestWrapper4.setAllowRedirects(true);
requestWrapper4.setOverrideQueryParams(new HashMap<>() {
{put("stateToken",stateToken); }
});
requestWrapper4.setHeader("Connection", "Keep-Alive");
requestWrapper4.setHeader("Host", "[redacted]");
requestWrapper4.setHeader("Accept", "text/html,application/xhtml+xml,application/xml" +
";q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
requestWrapper4.setHeader("Accept-Encoding", "gzip, deflate, br");
requestWrapper4.setHeader("Accept-Language", "en-US,en;q=0.9");
requestWrapper4.setHeader("Sec-Fetch-Dest","document");
requestWrapper4.setHeader("Sec-Fetch-Mode", "navigate");
requestWrapper4.setHeader("Sec-Fetch-Site", "same-origin");
requestWrapper4.addCookies(responseWrapper2.cookies);
requestWrapper4.addCookie("oktaStateToken", stateToken);
requestWrapper4.addCookie("t", "summer");
requestWrapper4.addCookie("DT", "DI0--aZ4ipPS8mFXhEWHFwXUw");
requestWrapper4.addCookie("ADRUM_BTa", "R:0|g:dd262b5c-ae86-4a1d-86aa-a89b3fed2bed|n:Okta_6d5b1e30-d05a-4894-a37b-81b5f6c60e0e");
requestWrapper4.addCookie("ADRUM_BT1", "R:0|i:617|e:41");
requestWrapper4.setHTTPMethod(Method.GET);
requestWrapper4.setHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36");
requestWrapper4.setBaseURL(new URL("[redacted]/login/step-up/redirect"));
ResponseWrapper responseWrapper4 = requestWrapper4.executeAndGetResponse();
当我正常使用浏览器进行身份验证时,在浏览器中进行这三个服务调用都没有问题,都返回200或302。然而,每当我使用RestAssured API运行这些服务时,我总是在执行第三个服务时得到403,不管作为查询参数{stateToken}传递进来的token是否合法。当这个参数没有通过RestAssured API传递进来时,我总是得到400,所以我知道这个方法调用是区分状态令牌是否传递进来的。
我的问题是:在上面的一系列步骤中,我是否有什么值得注意的地方遗漏了,导致总是通过一种媒介返回403,而不是通过Web浏览器?是否有什么东西可以防止使用RestAssured API进行验证?如果是这样,我是否有其他途径可以获得承载令牌?
我想到了几件事。
1.) 你的响应是否包含响应#2中的上一步链接?https:/developer.okta.comdocsreferenceapiauthn#response-example-after-authentication-and-mfa-are-complete-for-step-up-authentication-with-okta-session。
2.) 如果可能的话,我建议使用OAuth流(或SAML),而不是使用Authn API。
3.) Authn API是一个状态机,你不能总是假设你可以按照这个顺序执行这些请求。
Okta也有一个Authn SDK。https:/github.comoktaokta-auth-java。 (但我们再次建议尽可能使用OAuth)