以下描述一下成功对接FreeIpa认证的基本心路历程
技术 | 版本 |
---|---|
okhttp3 | 3.8.1 |
logging-interceptor | |
shiro-spring | 1.4.0 |
redisson | 3.10.2 |
springboot | 2.0.4.RELEASE |
public class HttpLogger implements HttpLoggingInterceptor.Logger {
@Override
public void log(String s) {
log.info(s);
}
}
/**
* Created by claire on 2019-09-10 - 15:02
**/
@Configuration
public class OkHttpClientConfig {
@Autowired
private ICacheService cacheService;
@Autowired
private IpaProperties ipaProperties;
private SSLSocketFactory createSSLSocketFactory() {
SSLSocketFactory ssfFactory = null;
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{new TrustCerts()}, new SecureRandom());
ssfFactory = sc.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return ssfFactory;
}
@Bean
public ConnectionPool pool() {
return new ConnectionPool(200, 5, TimeUnit.MINUTES);
}
@Bean
public OkHttpClient okHttpClient() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLogger());
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
.connectionPool(pool())
.sslSocketFactory(createSSLSocketFactory())
.cookieJar(new RequestCookieJar(cacheService,ipaProperties))
.hostnameVerifier((hostname, session) -> true)
.addNetworkInterceptor(loggingInterceptor);
return builder.build();
}
}
@Component
public class RequestCookieJar implements CookieJar {
public static final String LOGIN_SERVICE = "/ipa/session/login_password";
private ICacheService cacheService;
private IpaProperties ipaProperties;
private String loginRequestFullUrl="";
public RequestCookieJar(ICacheService cacheService,IpaProperties ipaProperties){
this.cacheService = cacheService;
this.ipaProperties = ipaProperties;
if(StringUtils.isNotBlank(ipaProperties.getBaseUrl())){
loginRequestFullUrl+= (ipaProperties.getBaseUrl()+LOGIN_SERVICE);
}
}
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
RListMultimapCache<String, CookieDTO> cookieListMap = cacheService.getCookieListMap();
if(!cookieListMap.containsKey(url.toString())){
if(cookies.size() != 0) {
List<CookieDTO> cookieDTOS = cookies.stream().map(this::transCookie2DTO).collect(Collectors.toList());
if(cookieDTOS.size() != 0) {
cookieListMap.putAll(url.toString(), cookieDTOS);
cookieListMap.expireKey(url.toString(), 29, TimeUnit.MINUTES);
}
}
}
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
if(!url.toString().contains(LOGIN_SERVICE)) {
RListMultimapCache<String, CookieDTO> cookieListMap = cacheService.getCookieListMap();
if (cookieListMap.containsKey(loginRequestFullUrl)) {
RList<CookieDTO> cookies = cookieListMap.get(loginRequestFullUrl);
if(cookies != null && cookies.size() !=0) {
List<Cookie> cookieList = cookies.stream().map(this::transDTO2Cookie).collect(Collectors.toList());
if(cookieList.size() != 0) {
return cookieList;
}
}
}
}
return Collections.emptyList();
}
private CookieDTO transCookie2DTO(Cookie cookie){
CookieDTO dto = new CookieDTO();
if(StringUtils.isNotBlank(cookie.domain())){
dto.setDomain(cookie.domain());
}
if(StringUtils.isNotBlank(cookie.name())){
dto.setName(cookie.name());
}
if(StringUtils.isNotBlank(cookie.path())){
dto.setPath(cookie.path());
}
if(StringUtils.isNotBlank(cookie.value())){
dto.setValue(cookie.value());
}
dto.setExpiresAt(cookie.expiresAt());
return dto;
}
private Cookie transDTO2Cookie(CookieDTO dto){
Cookie.Builder builder = new Cookie.Builder();
//secure = true
//httponly = true
//hostholy = false
builder.domain(dto.getDomain());
builder.expiresAt(dto.getExpiresAt());
builder.name(dto.getName());
builder.path(dto.getPath());
builder.value(dto.getValue());
return builder.build();
}
}
public class TrustCerts implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
@Override
public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public class IPAResponse {
private IPAResult result;
private String version;
private String error;
private String id;
private String principal;
public IPAResult getResult() {
return result;
}
public void setResult(IPAResult result) {
this.result = result;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPrincipal() {
return principal;
}
public void setPrincipal(String principal) {
this.principal = principal;
}
}
public class IPAResult {
private Map<String,Object> result;
private String value;
private String summary;
public Map<String, Object> getResult() {
return result;
}
public void setResult(Map<String, Object> result) {
this.result = result;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
}
@Slf4j
@Component
public class FreeIpaAuthenticationManager {
@Autowired
private ICacheService cacheService;
@Autowired
private IpaProperties ipaProperties;
public boolean auth(String user, String password) {
if (StringUtils.isNotBlank(ipaProperties.getBaseUrl())) {
String baseUrl = ipaProperties.getBaseUrl();
String refer = baseUrl + IPARequestConstant.LOGIN_SERVICE;
//header
Map<String, String> headMap = new HashMap<>();
headMap.put(HttpHeaders.REFERER, refer);
headMap.put(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN_VALUE);
headMap.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
//param
Map<String, String> params = new HashMap<>();
params.put(IPARequestConstant.USER_NAME, user);
params.put(IPARequestConstant.USER_PASSWORD, password);
//AUTH前,需清除之前的所有缓存
RListMultimapCache<String, CookieDTO> cookieListMap = cacheService.getCookieListMap();
cookieListMap.clear();
String response = HttpClientUtils.postFormParams(refer, params, headMap);
return null != response;
}
return false;
}
public void showUser(String username) throws IOException {
if (StringUtils.isNotBlank(ipaProperties.getBaseUrl())) {
String baseUrl = ipaProperties.getBaseUrl();
String refer = baseUrl + IPARequestConstant.LOOKUP_REFERER;
String requestUrl = baseUrl + IPARequestConstant.LOOKUP_SERVICE;
//param
String params = IPARequestConstant.buildUserRequestInfo(username);
//header
Map<String, String> headMap = new HashMap<>();
headMap.put(HttpHeaders.REFERER, refer);
headMap.put(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
headMap.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
String response = HttpClientUtils.postJsonParams(requestUrl, params, headMap);
if (StringUtils.isNotBlank(response)) {
ObjectMapper objectMapper = new ObjectMapper();
try {
IPAResponse ipaResponse = objectMapper.readValue(response, IPAResponse.class);
IPAResult result = ipaResponse.getResult();
} catch (Exception e) {
log.error("解析响应字符串异常,认证最终失败");
e.printStackTrace();
}
}
}
}
}
@Slf4j
public class HttpClientUtils {
private static String execNewCall(Request request){
Response response = null;
try {
OkHttpClient okHttpClient = SpringContextUtil.getBean(OkHttpClient.class);
response = okHttpClient.newCall(request).execute();
if(okHttpClient.cookieJar() != CookieJar.NO_COOKIES){
List<Cookie> cookies = Cookie.parseAll(request.url(), response.headers());
if(!cookies.isEmpty()){
okHttpClient.cookieJar().saveFromResponse(request.url(),cookies);
}
}
int status = response.code();
if (status == 200 && response.isSuccessful()) {
return response.body().string();
}
} catch (Exception e) {
log.error("okhttp3 put error >> ex = {}", ExceptionUtils.getStackTrace(e));
} finally {
if (response != null) {
response.close();
}
}
return null;
}
public static String postFormParams(String url, Map<String, String> params,Map<String, String> headerParamsMap) {
FormBody.Builder builder = new FormBody.Builder();
//添加参数
if (params != null && params.keySet().size() > 0) {
for (String key : params.keySet()) {
builder.add(key, params.get(key));
}
}
Request.Builder builder1 = new Request.Builder();
if(headerParamsMap != null && headerParamsMap.keySet().size()>0){
Headers headers = Headers.of(headerParamsMap);
builder1.headers(headers);
}
Request request = builder1
.url(url)
.post(builder.build())
.build();
return execNewCall(request);
}
public static String postJsonParams(String url, String jsonParams,Map<String, String> headerParamsMap ) {
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
Request.Builder builder = new Request.Builder()
.url(url)
.post(requestBody);
if(headerParamsMap != null && !headerParamsMap.isEmpty()) {
Headers headers = Headers.of(headerParamsMap);
builder.headers(headers);
}
return execNewCall(builder.build());
}
public static String postJsonParams(String url, String jsonParams) {
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
return execNewCall(request);
}
}
public class IPARequestConstant {
// URL
public static final String LOGIN_SERVICE = "/ipa/session/login_password";
public static final String LOOKUP_SERVICE = "/ipa/session/json";
public static final String LOOKUP_REFERER = "/ipa/ui/";
//request content
public static final String USER_NAME = "user";
public static final String USER_PASSWORD="password";
public static String buildUserRequestInfo(String username){
return "{\"method\":\"user_show/1\",\"params\":[[\"" + username + "\"],{\"all\":true,\"version\":\"2.229\"}]}";
}
}
@Test
public void testLogin() throws IOException {
if (authenticationManager.auth("user", "password")) {
authenticationManager.showUser("user");
}
}