提交 9465bb3c authored 作者: husishuai's avatar husishuai

更新注释,优化代码逻辑

上级 cccda9e5
package com.atlassian.jira.security.login;
/**
* @author husishuai
* @description
* @createTime 2024年02月22日
*/
import cn.hutool.json.JSONObject;
import com.atlassian.config.bootstrap.AtlassianBootstrapManager;
import com.atlassian.config.util.BootstrapUtils;
import com.atlassian.crowd.embedded.api.CrowdService;
import com.atlassian.crowd.embedded.api.Group;
import com.atlassian.crowd.exception.AccountNotFoundException;
import com.atlassian.crowd.exception.FailedAuthenticationException;
import com.atlassian.crowd.exception.runtime.CommunicationException;
import com.atlassian.crowd.exception.runtime.OperationFailedException;
import com.atlassian.event.api.EventPublisher;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.security.client.Oauth2ApiUtil;
import com.atlassian.jira.security.groups.GroupManager;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.user.UserDetails;
import com.atlassian.jira.user.util.UserManager;
import com.atlassian.jira.user.util.UserUtil;
import com.atlassian.seraph.auth.*;
import com.atlassian.seraph.elevatedsecurity.ElevatedSecurityGuard;
import com.atlassian.seraph.util.SecurityUtils;
import com.atlassian.spring.container.ContainerManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.Principal;
import java.util.Objects;
@AuthenticationContextAwareAuthenticator
public class JiraSeraphAuthenticatorOld extends DefaultAuthenticator {
private static final Logger log = LoggerFactory.getLogger(JiraSeraphAuthenticatorOld.class);
private EventPublisher eventPublisher;
//private UserAccessor userAccessor;
public JiraSeraphAuthenticatorOld() {
}
@Override
public boolean login(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String username, String password, boolean setRememberMeCookie) throws AuthenticatorException {
// 获取url中的请求参数code
String code = httpServletRequest.getParameter("code");
if(!StringUtils.hasLength(code)){
code = username;
}
System.out.println(String.format("conflunce登录,username -> %s , password -> %s , code -> %s", username, password, code));
AtlassianBootstrapManager bootstrapManager = BootstrapUtils.getBootstrapManager();
Boolean enabled = true;
Boolean isOSS = false;
JSONObject jsonObject = null;
JSONObject userinfo = null;
if (enabled && StringUtils.hasLength(code)) {
try {
// 开始请求oauth2接口
jsonObject = Oauth2ApiUtil.getInstance(bootstrapManager).findUserInfo(code);
if (Objects.isNull(jsonObject)) {
String remoteIP = httpServletRequest.getRemoteAddr();
String remoteHost = httpServletRequest.getRemoteHost();
return false;
} else if (jsonObject.getBool("success")) {
if (!jsonObject.getBool("success")) {
Oauth2ApiUtil.printServerResponseToWeb(httpServletResponse, String.format("认证登录失败,错误信息:%s", jsonObject.get("msg").toString()));
}
userinfo = jsonObject.getJSONObject("data");
//授权认证登录
username = userinfo.get("enName").toString();
String groupName = "jira-software-users";
// if(Objects.nonNull(userinfo.get("groupName"))){
// groupName = userinfo.get("groupName").toString();
// }
if (StringUtils.hasLength(username)) {
isOSS = true;
}
// 判断是否存在该用户,如果不存在则创建
Principal user = this.getUser(username);
if (ObjectUtils.isEmpty(user)) {
// 新增用户
UserManager userManager = getUserManager();
UserDetails userDetails = new UserDetails(username, username);
ApplicationUser applicationUser = userManager.createUser(userDetails);
// 获取操作组的对象 GroupManager
GroupManager groupManager = ComponentAccessor.getGroupManager();
// 检查是否存在该组,不存在则创建
if (!groupManager.groupExists(groupName)) {
groupManager.createGroup(groupName);
}
// 将用户添加到组
UserUtil userUtil = ComponentAccessor.getUserUtil();
Group group = groupManager.getGroup(groupName);
userUtil.addUserToGroup(group, applicationUser);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (username != null) {
httpServletRequest.setAttribute("com.atlassian.confluence.login.direct", true);
boolean result = this.doLogin(httpServletRequest, httpServletResponse, username, password, setRememberMeCookie,isOSS);
if (!result) {
String remoteIP = httpServletRequest.getRemoteAddr();
String remoteHost = httpServletRequest.getRemoteHost();
boolean captchaPresent = httpServletRequest.getParameterValues("captchaId") != null;
}
return result;
} else {
return false;
}
}
@Override
protected Principal getUser(String username) {
ApplicationUser user = this.getUserManager().getUserByName(username);
return user != null && user.isActive() ? user : null;
}
@Override
protected boolean authenticate(Principal user, String password) throws AuthenticatorException {
try {
System.out.println("ssssssssssssssssssssssssssssssssssssssss");
System.out.println("user -> "+user.getName());
System.out.println("password -> "+password);
this.crowdServiceAuthenticate(user, password);
return true;
} catch (AccountNotFoundException var4) {
System.out.println("authenticate : '" + user.getName() + "' does not exist and cannot be authenticated.");
return false;
} catch (FailedAuthenticationException var5) {
var5.printStackTrace();
System.out.println("authentication failed: '" + user.getName());
return false;
} catch (CommunicationException var6) {
throw new AuthenticatorException(AuthenticationErrorType.CommunicationError);
} catch (OperationFailedException var7) {
log.error("Error occurred while trying to authenticate user '" + user.getName() + "'.", var7);
throw new AuthenticatorException(AuthenticationErrorType.UnknownError);
}
}
@Override
protected Principal getUserFromSession(HttpServletRequest httpServletRequest) {
try {
if (httpServletRequest.getSession().getAttribute("seraph_defaultauthenticator_logged_out_user") != null) {
System.out.println(String.format("[%s] attribute is present in session", "seraph_defaultauthenticator_logged_out_user"));
return null;
} else {
Principal principal = (Principal)httpServletRequest.getSession().getAttribute("seraph_defaultauthenticator_user");
System.out.println(String.format("Located current user %s in session", principal));
return this.refreshPrincipalObtainedFromSession(httpServletRequest, principal);
}
} catch (RuntimeException var3) {
log.warn("Failed to extract user from session", var3);
return null;
}
}
protected EventPublisher getEventPublisher() {
if (this.eventPublisher == null) {
this.eventPublisher = (EventPublisher) ContainerManager.getInstance().getContainerContext().getComponent("eventPublisher");
}
return this.eventPublisher;
}
private void crowdServiceAuthenticate(Principal user, String password) throws FailedAuthenticationException {
Thread currentThread = Thread.currentThread();
ClassLoader origCCL = currentThread.getContextClassLoader();
try {
currentThread.setContextClassLoader(this.getClass().getClassLoader());
System.out.println("crowdService -> "+this.getCrowdService().getClass());
this.getCrowdService().authenticate(user.getName(), password);
} finally {
currentThread.setContextClassLoader(origCCL);
}
}
@Override
protected Principal getUserFromBasicAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
String METHOD = "getUserFromSession : ";
boolean dbg = log.isDebugEnabled();
String header = httpServletRequest.getHeader("Authorization");
LoginReason reason = LoginReason.OK;
if (SecurityUtils.isBasicAuthorizationHeader(header)) {
if (dbg) {
System.out.println("getUserFromSession : Looking in Basic Auth headers");
}
SecurityUtils.UserPassCredentials creds = SecurityUtils.decodeBasicAuthorizationCredentials(header);
ElevatedSecurityGuard securityGuard = this.getElevatedSecurityGuard();
if (!securityGuard.performElevatedSecurityCheck(httpServletRequest, creds.getUsername())) {
if (dbg) {
System.out.println("getUserFromSession : '" + creds.getUsername() + "' failed elevated security check");
}
reason = LoginReason.AUTHENTICATION_DENIED.stampRequestResponse(httpServletRequest, httpServletResponse);
securityGuard.onFailedLoginAttempt(httpServletRequest, creds.getUsername());
} else {
if (dbg) {
System.out.println("getUserFromSession : '" + creds.getUsername() + "' does not require elevated security check. Attempting authentication...");
}
try {
boolean loggedin = this.login(httpServletRequest, httpServletResponse, creds.getUsername(), creds.getPassword(), false);
if (loggedin) {
LoginReason.OK.stampRequestResponse(httpServletRequest, httpServletResponse);
securityGuard.onSuccessfulLoginAttempt(httpServletRequest, creds.getUsername());
if (dbg) {
System.out.println("getUserFromSession : Authenticated '" + creds.getUsername() + "' via Basic Auth");
}
return this.getUser(creds.getUsername());
}
reason = LoginReason.AUTHENTICATED_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
securityGuard.onFailedLoginAttempt(httpServletRequest, creds.getUsername());
} catch (AuthenticatorException var11) {
log.warn("getUserFromSession : Exception trying to login '" + creds.getUsername() + "' via Basic Auth:" + var11, var11);
}
}
try {
httpServletResponse.sendError(401, "Basic Authentication Failure - Reason : " + reason.toString());
} catch (IOException var10) {
log.warn("getUserFromSession : Exception trying to send Basic Auth failed error: " + var10, var10);
}
return null;
} else {
try {
httpServletResponse.setHeader("WWW-Authenticate", "Basic realm=\"protected-area\"");
httpServletResponse.sendError(401);
} catch (IOException var12) {
log.warn("getUserFromSession : Exception trying to send Basic Auth failed error: " + var12, var12);
}
return null;
}
}
private CrowdService getCrowdService() {
return (CrowdService) ComponentAccessor.getComponent(CrowdService.class);
}
private UserManager getUserManager() {
return ComponentAccessor.getUserManager();
}
public boolean doLogin(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, final String userName, String password, boolean setRememberMeCookie, Boolean isSSO) throws AuthenticatorException {
String METHOD = "login : ";
System.out.println(String.format("doLogin ->>>>>>> isSSO:%s , username:%s", isSSO,userName));
boolean dbg = log.isDebugEnabled();
Principal principal = new Principal() {
@Override
public String getName() {
return userName;
}
};
// boolean authenticated = this.authenticate(principal, password);
boolean authenticated = false;
if (isSSO) {
authenticated = true;
} else {
authenticated = this.authenticate(principal, password);
}
// if (dbg) {
System.out.println("login : '" + userName + "' has " + (authenticated ? "been" : "not been") + " authenticated");
// }
if (authenticated) {
Principal user = this.getUser(userName);
if(Objects.isNull(user)){
System.out.println("username -> %s 用户不存在");
}else{
System.out.println(String.format("获取用户成功,当前用户:%s", user.getName()));
}
if (this.authoriseUserAndEstablishSession(httpServletRequest, httpServletResponse, user)) {
if (setRememberMeCookie && httpServletResponse != null) {
this.getRememberMeService().addRememberMeCookie(httpServletRequest, httpServletResponse, userName);
}
System.out.println(String.format("authoriseUserAndEstablishSession,当前用户:%s", user.getName()));
return true;
}
System.out.println(String.format("AUTHORISATION_FAILED,当前用户:%s", user.getName()));
LoginReason.AUTHORISATION_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
} else {
System.out.println("login : '" + userName + "' could not be authenticated with the given password");
}
if (httpServletResponse != null) {
System.out.println("login : '" + userName + "' tried to login but they do not have USE permission or weren't found. Deleting remember me cookie.");
this.getRememberMeService().removeRememberMeCookie(httpServletRequest, httpServletResponse);
}
return false;
}
}
...@@ -8,9 +8,8 @@ package com.atlassian.jira.security.sso; ...@@ -8,9 +8,8 @@ package com.atlassian.jira.security.sso;
import cn.hutool.cache.CacheUtil; import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache; import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray; import cn.hutool.json.JSONArray;
...@@ -30,15 +29,18 @@ import com.atlassian.jira.user.UserDetails; ...@@ -30,15 +29,18 @@ import com.atlassian.jira.user.UserDetails;
import com.atlassian.jira.user.util.UserManager; import com.atlassian.jira.user.util.UserManager;
import com.atlassian.jira.user.util.UserUtil; import com.atlassian.jira.user.util.UserUtil;
import com.atlassian.seraph.auth.*; import com.atlassian.seraph.auth.*;
import com.atlassian.seraph.config.SecurityConfig;
import com.atlassian.seraph.elevatedsecurity.ElevatedSecurityGuard; import com.atlassian.seraph.elevatedsecurity.ElevatedSecurityGuard;
import com.atlassian.seraph.util.SecurityUtils; import com.atlassian.seraph.util.SecurityUtils;
import com.atlassian.spring.container.ContainerManager; import com.atlassian.spring.container.ContainerManager;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException; import java.io.IOException;
import java.security.Principal; import java.security.Principal;
import java.util.*; import java.util.*;
...@@ -47,18 +49,20 @@ import java.util.*; ...@@ -47,18 +49,20 @@ import java.util.*;
public class SSOSeraphAuthenticator extends DefaultAuthenticator { public class SSOSeraphAuthenticator extends DefaultAuthenticator {
// jira服务中的rest请求地址前缀 // 管理员的用户密码拼接后生成的base64加密串。格式: Basic base64(账号:密码)
private static final String BASE_URL = "http://192.168.1.113:8080/rest/api/2"; private static final String AUTHORIZATION_HEADER = "Basic cm9vdDpkZXZAbXNp"; // cm9vdDpkZXZAbXNp通过base64解析出来后就是root:dev@msi
// 管理员的用户密码拼接后生成的base64加密串。格式: base64(账号:密码)
private static final String AUTHORIZATION_HEADER = "Basic cm9vdDpBZG1pbkAxMjM="; // Replace with your base64 encoded auth header // jira容器内调用rest api接口请求地址前缀
private static final String BASE_URL = "http://localhost:8080/rest/api/2";
// 本地ip(验证是否为容器内部调用该方法时使用)
private static final String LOCAL_IP = "127.0.0.1";
// 本地缓存,过期时间为一天 // 本地缓存,过期时间为一天
private static final TimedCache<Object, Object> GROUP_NAME_CACHE = CacheUtil.newTimedCache((60 * 60 * 24 * 1000L)); private static final TimedCache<Object, Object> GROUP_NAME_CACHE = CacheUtil.newTimedCache((60 * 60 * 24 * 1000L));
// 日志 // 日志
private static final Logger log = LoggerFactory.getLogger(SSOSeraphAuthenticator.class); private static final Logger log = LoggerFactory.getLogger(SSOSeraphAuthenticator.class);
private EventPublisher eventPublisher;
//private UserAccessor userAccessor;
public SSOSeraphAuthenticator() { public SSOSeraphAuthenticator() {
} }
...@@ -88,7 +92,7 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator { ...@@ -88,7 +92,7 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator {
public boolean login(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String username, String password, boolean setRememberMeCookie) throws AuthenticatorException { public boolean login(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String username, String password, boolean setRememberMeCookie) throws AuthenticatorException {
// 登出时请求的地址 http://ip:port/logout.html // 登出时请求的地址 http://ip:port/logout.html
String isLogout = httpServletRequest.getParameter("isLogout"); String isLogout = httpServletRequest.getParameter("isLogout");
if (isLogout.equals("true")) { if ("true".equals(isLogout)) {
this.logout(httpServletRequest, httpServletResponse); this.logout(httpServletRequest, httpServletResponse);
}else { }else {
// jira请求标识 // jira请求标识
...@@ -110,10 +114,22 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator { ...@@ -110,10 +114,22 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator {
// return false; // return false;
// } // }
// 获取请求的ip地址
// String clientIp1 = httpServletRequest.getHeader("X-Forwarded-For"); // 代理转发的ip地址
// String clientIp2 = httpServletRequest.getLocalAddr(); // 容器内的IP地址
String clientIp = httpServletRequest.getRemoteAddr(); // 客户端ip地址
// 3. 判断:用户是否走了登录页进行登录(保证原有登录页可以正常登录) // 3. 判断:用户是否走了登录页进行登录(保证原有登录页可以正常登录)
// 如果是空,则表示未走登录页。那么从auap中获取用户名称 /**
if (CharSequenceUtil.isBlank(username) && CharSequenceUtil.isBlank(password)) { * 如果账号密码为空,则表示未走登录页(走页面前端做了校验的,用户正常使用是必须输入账号密码的)
* 如果clientIp不是本地ip,则走单点登录认证,如果是127.0.0.1,则说明当次请求是内部调用认证,则走密码认证
*
* 判断clientIp的原因:
* 在方法addGroupApplicationRole()中,存在两个调用内部rest api的接口
* 既然是容器内部,则通过127.0.0.1进行判断是否为内部调用
*/
if (CharSequenceUtil.isBlank(username) && CharSequenceUtil.isBlank(password) && !LOCAL_IP.equals(clientIp)) {
System.out.println("sso认证...");
// 3.1 获取:用户、组信息 // 3.1 获取:用户、组信息
/** /**
* auap获取用户的代码 * auap获取用户的代码
...@@ -125,8 +141,8 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator { ...@@ -125,8 +141,8 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator {
HashMap<String, Object> auapUserInfo = new HashMap<>(); HashMap<String, Object> auapUserInfo = new HashMap<>();
auapUserInfo.put("username", "zhangsan"); auapUserInfo.put("username", "zhangsan");
auapUserInfo.put("staTruename", "张三"); auapUserInfo.put("staTruename", "张三");
auapUserInfo.put("deptId", "1813"); auapUserInfo.put("deptId", "1234");
auapUserInfo.put("deptName", "分公司一-七组"); auapUserInfo.put("deptName", "测试组");
// auap账号名称 // auap账号名称
username = auapUserInfo.get("username").toString(); username = auapUserInfo.get("username").toString();
...@@ -140,36 +156,49 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator { ...@@ -140,36 +156,49 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator {
String groupName = deptName + "-" + deptId; String groupName = deptName + "-" + deptId;
try { try {
// 3.2 查询用户是否存在(不存在则创建) // 3.2 判断是否存在组
GroupManager groupManager = ComponentAccessor.getGroupManager();
boolean groupExists = groupManager.groupExists(groupName);
// 判断当前组在缓存中是否不存在
if (!GROUP_NAME_CACHE.containsKey(groupName)) {
// 如果组在缓存中不存在,则创建组
if (!groupExists) {
groupManager.createGroup(groupName);
// 给组授予应用程序访问权,否则无法登陆(调用rest api实现)
this.addGroupApplicationRole(groupName);
}
GROUP_NAME_CACHE.put(groupName, groupName);
}
// 获取用户对象 // 获取用户对象
Principal user = this.getUser(username); Principal user = this.getUser(username);
UserUtil userUtil = ComponentAccessor.getUserUtil();
Group group = groupManager.getGroup(groupName);
UserManager userManager = getUserManager();
// 如果用户不存在,则创建用户 // 如果用户不存在,则创建用户
if (ObjectUtils.isEmpty(user)) { if (ObjectUtils.isEmpty(user)) {
// 3.3 判断是否存在组 // 3.3 查询用户是否存在(不存在则创建)
GroupManager groupManager = ComponentAccessor.getGroupManager(); // 新增用户(密码和邮箱非必填,但是最好给个默认的密码,保证非sso登录也可以正常使用,根据业务场景而定)
// 判断缓存中是否存在用户组
if (!GROUP_NAME_CACHE.containsKey(groupName)) {
boolean groupExists = groupManager.groupExists(groupName);
// 不存在则创建组
if (!groupExists) {
groupManager.createGroup(groupName);
// 给组授予应用程序访问权,否则无法登陆(调用rest api实现)
addGroupApplicationRole(groupName);
}
// 将组添加至缓存
GROUP_NAME_CACHE.put(groupName, groupName);
}
// 新增用户
UserManager userManager = getUserManager();
UserDetails userDetails = new UserDetails(username, userFullName).withPassword("123456").withEmail(username + "@test.com"); UserDetails userDetails = new UserDetails(username, userFullName).withPassword("123456").withEmail(username + "@test.com");
ApplicationUser applicationUser = userManager.createUser(userDetails); ApplicationUser applicationUser = userManager.createUser(userDetails);
// 将用户添加到组 // 将用户添加到组
UserUtil userUtil = ComponentAccessor.getUserUtil();
Group group = groupManager.getGroup(groupName);
userUtil.addUserToGroup(group, applicationUser); userUtil.addUserToGroup(group, applicationUser);
}else {
System.out.println("用户已存在...");
ApplicationUser userByName = userManager.getUserByName(username);
// 获取当前用户所属组
Collection<String> groupNamesForUser = groupManager.getGroupNamesForUser(Objects.requireNonNull(userByName));
// 组中不存在当前组则添加组
if (CollUtil.isNotEmpty(groupNamesForUser) && !groupNamesForUser.contains(groupName)) {
System.out.println("添加组..");
userUtil.addUserToGroup(group, userByName);
} else if (CollUtil.isEmpty(groupNamesForUser)) {
System.out.println("没有组...");
userUtil.addUserToGroup(groupManager.getGroup("jira-software-users"), userByName);
userUtil.addUserToGroup(group, userByName);
}
} }
}catch (Exception e) { }catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
...@@ -177,6 +206,7 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator { ...@@ -177,6 +206,7 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator {
// 单点登录验证 // 单点登录验证
return this.doLogin(httpServletRequest, httpServletResponse, username, password, setRememberMeCookie,true); return this.doLogin(httpServletRequest, httpServletResponse, username, password, setRememberMeCookie,true);
}else { }else {
System.out.println("密码认证...");
// 用户名及密码登录校验 // 用户名及密码登录校验
return this.doLogin(httpServletRequest, httpServletResponse, username, password, setRememberMeCookie,false); return this.doLogin(httpServletRequest, httpServletResponse, username, password, setRememberMeCookie,false);
} }
...@@ -185,172 +215,48 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator { ...@@ -185,172 +215,48 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator {
} }
@Override /**
protected Principal getUser(String username) { * 开始登录验证,sso登录直接登录成功,账号密码则会校验账号密码(成功后会创建session、cookie)
ApplicationUser user = this.getUserManager().getUserByName(username); * @param httpServletRequest
return user != null && user.isActive() ? user : null; * @param httpServletResponse
} * @param userName
* @param password
@Override * @param setRememberMeCookie
protected boolean authenticate(Principal user, String password) throws AuthenticatorException { * @param isSSO
try { * @return
System.out.println("user -> " + user.getName()); * @throws AuthenticatorException
System.out.println("password -> " + password); */
this.crowdServiceAuthenticate(user, password);
return true;
} catch (AccountNotFoundException var4) {
System.out.println("authenticate : '" + user.getName() + "' does not exist and cannot be authenticated.");
return false;
} catch (FailedAuthenticationException var5) {
var5.printStackTrace();
System.out.println("authentication failed: '" + user.getName());
return false;
} catch (CommunicationException var6) {
throw new AuthenticatorException(AuthenticationErrorType.CommunicationError);
} catch (OperationFailedException var7) {
log.error("Error occurred while trying to authenticate user '" + user.getName() + "'.", var7);
throw new AuthenticatorException(AuthenticationErrorType.UnknownError);
}
}
@Override
protected Principal getUserFromSession(HttpServletRequest httpServletRequest) {
try {
if (httpServletRequest.getSession().getAttribute("seraph_defaultauthenticator_logged_out_user") != null) {
System.out.println(String.format("[%s] attribute is present in session", "seraph_defaultauthenticator_logged_out_user"));
return null;
} else {
Principal principal = (Principal) httpServletRequest.getSession().getAttribute("seraph_defaultauthenticator_user");
System.out.println(String.format("Located current user %s in session", principal));
return this.refreshPrincipalObtainedFromSession(httpServletRequest, principal);
}
} catch (RuntimeException var3) {
log.warn("Failed to extract user from session", var3);
return null;
}
}
protected EventPublisher getEventPublisher() {
if (this.eventPublisher == null) {
this.eventPublisher = (EventPublisher) ContainerManager.getInstance().getContainerContext().getComponent("eventPublisher");
}
return this.eventPublisher;
}
private void crowdServiceAuthenticate(Principal user, String password) throws FailedAuthenticationException {
Thread currentThread = Thread.currentThread();
ClassLoader origCCL = currentThread.getContextClassLoader();
try {
currentThread.setContextClassLoader(this.getClass().getClassLoader());
System.out.println("crowdService -> " + this.getCrowdService().getClass());
this.getCrowdService().authenticate(user.getName(), password);
} finally {
currentThread.setContextClassLoader(origCCL);
}
}
@Override
protected Principal getUserFromBasicAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
String METHOD = "getUserFromSession : ";
boolean dbg = log.isDebugEnabled();
String header = httpServletRequest.getHeader("Authorization");
LoginReason reason = LoginReason.OK;
if (SecurityUtils.isBasicAuthorizationHeader(header)) {
if (dbg) {
System.out.println("getUserFromSession : Looking in Basic Auth headers");
}
SecurityUtils.UserPassCredentials creds = SecurityUtils.decodeBasicAuthorizationCredentials(header);
ElevatedSecurityGuard securityGuard = this.getElevatedSecurityGuard();
if (!securityGuard.performElevatedSecurityCheck(httpServletRequest, creds.getUsername())) {
if (dbg) {
System.out.println("getUserFromSession : '" + creds.getUsername() + "' failed elevated security check");
}
reason = LoginReason.AUTHENTICATION_DENIED.stampRequestResponse(httpServletRequest, httpServletResponse);
securityGuard.onFailedLoginAttempt(httpServletRequest, creds.getUsername());
} else {
if (dbg) {
System.out.println("getUserFromSession : '" + creds.getUsername() + "' does not require elevated security check. Attempting authentication...");
}
try {
boolean loggedin = this.login(httpServletRequest, httpServletResponse, creds.getUsername(), creds.getPassword(), false);
if (loggedin) {
LoginReason.OK.stampRequestResponse(httpServletRequest, httpServletResponse);
securityGuard.onSuccessfulLoginAttempt(httpServletRequest, creds.getUsername());
if (dbg) {
System.out.println("getUserFromSession : Authenticated '" + creds.getUsername() + "' via Basic Auth");
}
return this.getUser(creds.getUsername());
}
reason = LoginReason.AUTHENTICATED_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
securityGuard.onFailedLoginAttempt(httpServletRequest, creds.getUsername());
} catch (AuthenticatorException var11) {
log.warn("getUserFromSession : Exception trying to login '" + creds.getUsername() + "' via Basic Auth:" + var11, var11);
}
}
try {
httpServletResponse.sendError(401, "Basic Authentication Failure - Reason : " + reason.toString());
} catch (IOException var10) {
log.warn("getUserFromSession : Exception trying to send Basic Auth failed error: " + var10, var10);
}
return null;
} else {
try {
httpServletResponse.setHeader("WWW-Authenticate", "Basic realm=\"protected-area\"");
httpServletResponse.sendError(401);
} catch (IOException var12) {
log.warn("getUserFromSession : Exception trying to send Basic Auth failed error: " + var12, var12);
}
return null;
}
}
private CrowdService getCrowdService() {
return (CrowdService) ComponentAccessor.getComponent(CrowdService.class);
}
private UserManager getUserManager() {
return ComponentAccessor.getUserManager();
}
public boolean doLogin(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, final String userName, String password, boolean setRememberMeCookie, Boolean isSSO) throws AuthenticatorException { public boolean doLogin(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, final String userName, String password, boolean setRememberMeCookie, Boolean isSSO) throws AuthenticatorException {
String METHOD = "login : "; String METHOD = "login : ";
System.out.println(String.format("doLogin ->>>>>>> isSSO:%s , username:%s", isSSO, userName)); System.out.println(String.format("doLogin ->>>>>>> isSSO:%s , username:%s", isSSO, userName));
boolean dbg = log.isDebugEnabled(); // 创建用户对象
Principal principal = new Principal() { Principal principal = new Principal() {
@Override @Override
public String getName() { public String getName() {
return userName; return userName;
} }
}; };
// 原本默认的登录方法
// boolean authenticated = this.authenticate(principal, password); // boolean authenticated = this.authenticate(principal, password);
boolean authenticated = false; boolean authenticated = false;
if (isSSO) { if (isSSO) {
authenticated = true; authenticated = true; // 单点登录(如果走到当前行,可以百分之百保证,用户已经校验成功-在jira中已经创建成功-用户组已经授权成功)
} else { } else {
authenticated = this.authenticate(principal, password); authenticated = this.authenticate(principal, password); // 账号密码校验登录
} }
// if (dbg) {
System.out.println("login : '" + userName + "' has " + (authenticated ? "been" : "not been") + " authenticated"); System.out.println("login : '" + userName + "' has " + (authenticated ? "been" : "not been") + " authenticated");
// }
// 如果为true,则创建session、cookie
if (authenticated) { if (authenticated) {
Principal user = this.getUser(userName); Principal user = this.getUser(userName);
System.out.println("user是否为空 = " + user);
if (Objects.isNull(user)) { if (Objects.isNull(user)) {
System.out.println("username -> %s 用户不存在"); System.out.println("username -> %s 用户不存在");
} else { } else {
System.out.println(String.format("获取用户成功,当前用户:%s", user.getName())); System.out.println(String.format("获取用户成功,当前用户:%s", user.getName()));
} }
// this.authoriseUserAndEstablishSession(httpServletRequest, httpServletResponse, user)
// 该方法,也就是导致用户没有组时第一次无法正常登录的入口,当前类中将所需的方法进行重写,不走原本的方法逻辑,具体看下一部分的注释
if (this.authoriseUserAndEstablishSession(httpServletRequest, httpServletResponse, user)) { if (this.authoriseUserAndEstablishSession(httpServletRequest, httpServletResponse, user)) {
if (setRememberMeCookie && httpServletResponse != null) { if (setRememberMeCookie && httpServletResponse != null) {
this.getRememberMeService().addRememberMeCookie(httpServletRequest, httpServletResponse, userName); this.getRememberMeService().addRememberMeCookie(httpServletRequest, httpServletResponse, userName);
...@@ -372,22 +278,79 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator { ...@@ -372,22 +278,79 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator {
return false; return false;
} }
// ------------start
// 这部分主要解决 用户没有组时,在执行login方法给用户添加组后,依然无法正常登录的问题
// 但是现在可以正常登录,依然存在bug:登录进去以后,需要手动刷新一次页面,之后就没有问题了
// 正常不会出现这种情况,只有管理员把用户的所有组都移除后才会出现问题。并且就算出现问题,刷新一次后,后续也不会再次出现
// TODO 彻底解决需要研究方法:boolean canLogin = this.isAuthorised(httpServletRequest, principal);
// 目前没找到详细实现,只用到public boolean canLogin(Principal user, HttpServletRequest request)解决登录问题
public boolean canLogin(Principal user, HttpServletRequest request) {
return user != null;
}
protected void putPrincipalInSessionContext(HttpServletRequest httpServletRequest, Principal principal) {
HttpSession httpSession = httpServletRequest.getSession();
httpSession.setAttribute("seraph_defaultauthenticator_user", principal);
httpSession.setAttribute("seraph_defaultauthenticator_user_id", principal != null ? principal.getName() : null);
httpSession.setAttribute("seraph_defaultauthenticator_logged_out_user", (Object)null);
}
protected boolean authoriseUserAndEstablishSession(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Principal principal) {
boolean principalAlreadyInSessionContext = this.isPrincipalAlreadyInSessionContext(httpServletRequest, principal);
this.putPrincipalInSessionContext(httpServletRequest, (Principal)null);
boolean canLogin = this.isAuthorised(httpServletRequest, principal);
if (log.isDebugEnabled()) {
String prefix = "authoriseUser : '" + principal.getName() + "' ";
log.debug(prefix + (canLogin ? "can" : "CANNOT") + " login according to the RoleMapper");
}
if (canLogin) {
if (!principalAlreadyInSessionContext) {
SecurityConfig theConfig = this.getConfig();
if (theConfig != null && theConfig.isInvalidateSessionOnLogin()) {
this.invalidateSession(httpServletRequest);
}
}
this.putPrincipalInSessionContext(httpServletRequest, principal);
return true;
} else {
return false;
}
}
// 保留 private void invalidateSession(HttpServletRequest httpServletRequest) {
SessionInvalidator si = new SessionInvalidator(this.getConfig().getInvalidateSessionExcludeList());
si.invalidateSession(httpServletRequest);
}
protected boolean isAuthorised(HttpServletRequest httpServletRequest, Principal principal) {
// 原本默认的方法(在系统中存在用户,但是该用户不存在任何组时,通过代码授予组信息时首次登录失败,所以使用下面的canLogin方法)
// return this.getRoleMapper().canLogin(principal, httpServletRequest);
return this.canLogin(principal, httpServletRequest);
}
// ------------end
// ------------start 创建组以及给组授权应用访问权(以下两个方法都调用了jira内部的rest api接口)
/** /**
* 获取应用程序授权信息 * 获取应用程序授权信息(以下链接页面中的列表数据,拿到列表数据在给组授权时,需要将原本的这些列表原封不动的请求回去,否则会导致原本的授权信息丢失)
* 具体页面为:http://192.168.1.113:8088/secure/admin/ApplicationAccess.jspa
* 该页面中,必须要有新建的组
* @return 响应 * @return 响应
*/ */
private HashMap<String, List<String>> getApplicationRole() { private HashMap<String, List<String>> getApplicationRole() {
// 结果集 // 响应结果集
HashMap<String, List<String>> resultMap = new HashMap<>(); HashMap<String, List<String>> resultMap = new HashMap<>();
// 请求
HttpRequest request = HttpRequest.get(BASE_URL + "/applicationrole") HttpRequest request = HttpRequest.get(BASE_URL + "/applicationrole")
.header("Authorization", AUTHORIZATION_HEADER); .header("Authorization", AUTHORIZATION_HEADER);
HttpResponse response = request.execute(); HttpResponse response = request.execute();
String body = response.body(); String body = response.body();
// 解析 // 解析body
// 将JSON字符串转换为JSONArray // 将JSON字符串转换为JSONArray
JSONArray jsonArray = JSONUtil.parseArray(body); JSONArray jsonArray = JSONUtil.parseArray(body);
// 保存原本默认组中的数据 // 保存原本默认组中的数据
...@@ -414,29 +377,30 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator { ...@@ -414,29 +377,30 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator {
resultMap.put("groups", groups); resultMap.put("groups", groups);
resultMap.put("defaultGroups", defaultGroups); resultMap.put("defaultGroups", defaultGroups);
} }
// 返回结果集
return resultMap; return resultMap;
} }
/** /**
* 给组添加应用权限 * 给组添加应用权限(新创建的组必须授予应用权限,否则该组中的用户无法正常登录)
*/ */
private void addGroupApplicationRole(String groupName) { private void addGroupApplicationRole(String groupName) {
// 获取应用程序授权信息(包含原本已授权的信息) // 获取应用程序授权信息(包含原本已授权的信息)
HashMap<String, List<String>> applicationRole = getApplicationRole(); HashMap<String, List<String>> applicationRole = getApplicationRole();
// 原本的组
List<String> groups = applicationRole.get("groups"); List<String> groups = applicationRole.get("groups");
// 添加新增的组信息 // 添加新增的组信息
if (!groups.contains(groupName)) { if (!groups.contains(groupName)) {
groups.add(groupName); groups.add(groupName);
} }
// 原本默认的组信息 // 原本默认的组(也就是:http://192.168.1.113:8088/secure/admin/ApplicationAccess.jspa页面里列表被勾选的那个选项,是否为默认)
List<String> defaultGroups = applicationRole.get("defaultGroups"); List<String> defaultGroups = applicationRole.get("defaultGroups");
// 创建请求对象 // 创建请求对象
/** 格式 /** 格式
* { * {
* "groups": [ * "groups": [
* "分公司一-七组-1813", * "测试组-1234",
* "jira-administrators", * "jira-administrators",
* "jira-software-users" * "jira-software-users"
* ], * ],
...@@ -459,4 +423,129 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator { ...@@ -459,4 +423,129 @@ public class SSOSeraphAuthenticator extends DefaultAuthenticator {
HttpResponse response = request.execute(); HttpResponse response = request.execute();
} }
// ------------start
// -----------------------以下方法为JiraSeraphAuthenticator类中原本存在的
@Override
protected Principal getUser(String username) {
ApplicationUser user = this.getUserManager().getUserByName(username);
return user != null && user.isActive() ? user : null;
}
@Override
protected boolean authenticate(Principal user, String password) throws AuthenticatorException {
try {
this.crowdServiceAuthenticate(user, password);
return true;
} catch (AccountNotFoundException var4) {
System.out.println("authenticate : '" + user.getName() + "' does not exist and cannot be authenticated.");
return false;
} catch (FailedAuthenticationException var5) {
log.debug("authentication failed: '" + user.getName(), var5);
return false;
} catch (CommunicationException var6) {
throw new AuthenticatorException(AuthenticationErrorType.CommunicationError);
} catch (OperationFailedException var7) {
log.error("Error occurred while trying to authenticate user '" + user.getName() + "'.", var7);
throw new AuthenticatorException(AuthenticationErrorType.UnknownError);
}
}
private void crowdServiceAuthenticate(Principal user, String password) throws FailedAuthenticationException {
Thread currentThread = Thread.currentThread();
ClassLoader origCCL = currentThread.getContextClassLoader();
try {
currentThread.setContextClassLoader(this.getClass().getClassLoader());
this.getCrowdService().authenticate(user.getName(), password);
} finally {
currentThread.setContextClassLoader(origCCL);
}
}
protected Principal refreshPrincipalObtainedFromSession(HttpServletRequest httpServletRequest, Principal principal) {
Principal freshPrincipal = principal;
if (principal != null && principal.getName() != null) {
freshPrincipal = this.getUser(principal.getName());
this.putPrincipalInSessionContext(httpServletRequest, freshPrincipal);
}
return freshPrincipal;
}
@Override
protected Principal getUserFromBasicAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
String METHOD = "getUserFromSession : ";
boolean dbg = log.isDebugEnabled();
String header = httpServletRequest.getHeader("Authorization");
LoginReason reason = LoginReason.OK;
if (SecurityUtils.isBasicAuthorizationHeader(header)) {
if (dbg) {
System.out.println("getUserFromSession : Looking in Basic Auth headers");
}
SecurityUtils.UserPassCredentials creds = SecurityUtils.decodeBasicAuthorizationCredentials(header);
ElevatedSecurityGuard securityGuard = this.getElevatedSecurityGuard();
if (!securityGuard.performElevatedSecurityCheck(httpServletRequest, creds.getUsername())) {
if (dbg) {
System.out.println("getUserFromSession : '" + creds.getUsername() + "' failed elevated security check");
}
reason = LoginReason.AUTHENTICATION_DENIED.stampRequestResponse(httpServletRequest, httpServletResponse);
securityGuard.onFailedLoginAttempt(httpServletRequest, creds.getUsername());
} else {
if (dbg) {
System.out.println("getUserFromSession : '" + creds.getUsername() + "' does not require elevated security check. Attempting authentication...");
}
try {
boolean loggedin = this.login(httpServletRequest, httpServletResponse, creds.getUsername(), creds.getPassword(), false);
if (loggedin) {
LoginReason.OK.stampRequestResponse(httpServletRequest, httpServletResponse);
securityGuard.onSuccessfulLoginAttempt(httpServletRequest, creds.getUsername());
if (dbg) {
System.out.println("getUserFromSession : Authenticated '" + creds.getUsername() + "' via Basic Auth");
}
return this.getUser(creds.getUsername());
}
reason = LoginReason.AUTHENTICATED_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
securityGuard.onFailedLoginAttempt(httpServletRequest, creds.getUsername());
} catch (AuthenticatorException var11) {
log.warn("getUserFromSession : Exception trying to login '" + creds.getUsername() + "' via Basic Auth:" + var11, var11);
}
}
try {
httpServletResponse.sendError(401, "Basic Authentication Failure - Reason : " + reason.toString());
} catch (IOException var10) {
log.warn("getUserFromSession : Exception trying to send Basic Auth failed error: " + var10, var10);
}
return null;
} else {
try {
httpServletResponse.setHeader("WWW-Authenticate", "Basic realm=\"protected-area\"");
httpServletResponse.sendError(401);
} catch (IOException var12) {
log.warn("getUserFromSession : Exception trying to send Basic Auth failed error: " + var12, var12);
}
return null;
}
}
private CrowdService getCrowdService() {
return (CrowdService)ComponentAccessor.getComponent(CrowdService.class);
}
private UserManager getUserManager() {
return ComponentAccessor.getUserManager();
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论