基于Azure AD作为IDP的SAML认证RestAssured实现问题
解决RestAssured处理SAML+Ping Federator+Azure AD SSO登录的问题
问题背景
现有基于SAML认证、Azure AD作为IDP的应用,SSO登录流程如下:
- 请求SAML重定向URL
/Saml/SAMLLoginRedirect - 自动重定向至Ping Federator,重定向URL包含
SAMLRequestToken和RelayState,最终响应返回带新令牌的提交表单 - 使用该响应参数请求IDP地址
login.microsoftonline.com//saml2未达预期
已通过JMeter解决:开启跟随重定向,提取首个请求头中的URL,携带Cookie重新请求Ping Federator后完成IDP流程,但RestAssured中遇到以下问题:
- 启用重定向无法捕获中间响应头信息,后续处理失败
- 禁用重定向虽能获取重定向URL,但携带Cookie请求该URL时返回500错误,无法获取预期响应与Cookie
所有到IDP前的请求均为GET请求。
解决方案
1. 自定义重定向策略捕获中间会话信息
RestAssured默认的重定向处理会自动跳转,无法捕获中间步骤的响应头和Cookie。通过自定义RedirectStrategy,可以在跟随重定向的同时记录关键信息,保留完整会话上下文。
自定义重定向策略代码:
import io.restassured.RestAssured; import io.restassured.config.RedirectConfig; import io.restassured.config.RestAssuredConfig; import org.apache.http.Header; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.ProtocolException; import org.apache.http.client.RedirectStrategy; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.DefaultRedirectStrategy; import org.apache.http.protocol.HttpContext; import java.util.HashMap; import java.util.Map; public class CustomRedirectStrategy extends DefaultRedirectStrategy { private String pingFederatorRedirectUrl; private final Map<String, String> sessionCookies = new HashMap<>(); @Override public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { boolean isRedirect = super.isRedirected(request, response, context); if (isRedirect) { // 提取重定向URL pingFederatorRedirectUrl = response.getFirstHeader("Location").getValue(); // 提取所有Set-Cookie头,整理为键值对 Header[] cookieHeaders = response.getHeaders("Set-Cookie"); for (Header header : cookieHeaders) { String cookiePair = header.getValue().split(";")[0]; String[] keyValue = cookiePair.split("=", 2); if (keyValue.length == 2) { sessionCookies.put(keyValue[0].trim(), keyValue[1].trim()); } } } return isRedirect; } public String getPingFederatorRedirectUrl() { return pingFederatorRedirectUrl; } public Map<String, String> getSessionCookies() { return sessionCookies; } }
测试代码中使用该策略:
// 初始化自定义重定向策略 CustomRedirectStrategy customRedirectStrategy = new CustomRedirectStrategy(); // 配置RestAssured启用自定义重定向逻辑 RestAssured.config = RestAssuredConfig.config() .redirect(RedirectConfig.redirectConfig() .followRedirects(true) .redirectStrategy(customRedirectStrategy)); // 第一步:请求SAMLLoginRedirect,触发重定向并捕获信息 RestAssured.given() .when() .get("/Saml/SAMLLoginRedirect") .then() .statusCode(200); // 获取捕获的Ping Federator地址和会话Cookie String pingUrl = customRedirectStrategy.getPingFederatorRedirectUrl(); Map<String, String> cookies = customRedirectStrategy.getSessionCookies(); // 第二步:请求Ping Federator,携带完整会话Cookie String pingResponse = RestAssured.given() .cookies(cookies) .when() .get(pingUrl) .then() .statusCode(200) .extract() .asString(); // 第三步:解析Ping响应中的表单参数,请求Azure AD IDP // 使用Jsoup解析HTML表单(需引入Jsoup依赖) org.jsoup.nodes.Document doc = org.jsoup.Jsoup.parse(pingResponse); org.jsoup.nodes.Element form = doc.selectFirst("form"); String samlRequest = form.selectFirst("input[name='SAMLRequest']").val(); String relayState = form.selectFirst("input[name='RelayState']").val(); String idpUrl = form.attr("action"); // 提交表单到Azure AD IDP(注意表单method可能为POST) RestAssured.given() .formParam("SAMLRequest", samlRequest) .formParam("RelayState", relayState) .when() .post(idpUrl) .then() .statusCode(200);
2. 确保携带完整会话Cookie(禁用重定向场景)
如果选择禁用自动重定向,需确保请求Ping Federator时携带第一步请求返回的所有Cookie,而非仅重定向响应中的Cookie,避免因会话不完整导致500错误。
示例代码:
// 第一步:禁用重定向,请求SAMLLoginRedirect io.restassured.response.Response firstResponse = RestAssured.given() .redirects().follow(false) .when() .get("/Saml/SAMLLoginRedirect"); // 获取所有会话Cookie和重定向URL Map<String, String> allCookies = firstResponse.getCookies(); String pingUrl = firstResponse.getHeader("Location"); // 第二步:携带所有Cookie请求Ping Federator io.restassured.response.Response pingResponse = RestAssured.given() .cookies(allCookies) // 可选:添加Referer、User-Agent等请求头模拟浏览器行为 .header("Referer", "你的应用域名/Saml/SAMLLoginRedirect") .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36") .when() .get(pingUrl); // 后续解析表单并请求IDP的步骤同前...
3. 验证请求头完整性
部分场景下,Ping Federator会验证请求的Referer、User-Agent等头信息,确保请求来自合法来源。如果遇到500错误,可添加这些头信息模拟浏览器请求,提升兼容性。
内容的提问来源于stack exchange,提问作者Sasitharan
相关产品推荐
相关产品推荐

