background
Most internal applications use the Central Authentication Service (CAS) to authenticate user login. If each application connects to domain account authentication separately, it will not only waste effort, but also cannot guarantee security. The common solution implements login authentication and Single Sign On (SSO) for the deployment of a CAS service. Instead of a bloated open source project solution, or building your own wheel, there is a lightweight solution -> Implementing CAS through GitLab’s Applications.
CAS
There are a lot of related materials on the Internet. Here we only describe the basic interaction process
node "APP" AS c
node "CAS Server" AS s
node "Web Browser" AS b
b -up-> c: 1. request
c -> s: 2. redirect login page
b <-up-> s: 3. login
s -> c: 4. ticket
c -> s: 5. valid tocket
s -> c: 6. user info
Copy the code
implementation
Gitlab is used as an authorization server to interact with Gitlab Applications through code and call apis to obtain user information.
Gitlab CAS
The CAS interaction process is basically followed, and some fields are named differently.
actor User as u
participant Gitlab as g
u -> app: request
app -> app: valid session authorization
alt authorization login
app -> u: view
else
app -> u: redirect login page
u -> g: submit login form
g -> app: redirect callbackUrl with authorization code
app -> g: get access token by authorization code
g -> app: return access token
app -> g: get user info
g -> app: return user info
g -> g: store user info with authorization key
g -> u: set cookie authorization key
u -> app: redirect referer url
app -> app: valid session authorization
app -> u: view
end
Copy the code
Code implementation
clientId
&Secret
By creating aGitlab applications
To obtain- Through the browser, so
callback
The address can belocalhost
- User information can be stored or JWT
- The code is a sample code and can be encapsulated according to requirements in actual use
starter
@Controller
public class OauthController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${oauth2.server.url:https://gitlab.com}")
private String gitlabServerUrl;
@Value("${oauth2.client.id:xxx}")
private String clientId;
@Value("${oauth2.client.secret:xxxx}")
private String clientSecret;
@Value("${oauth2.client.callback.url:http://localhost:9000/callback}")
private String callbackUrl;
private static final String CURRENT_USER = "CurrentUser";
private static final String AUTHORIZATION_KEY = "Authorization";
private Map<String, User> userStore = new HashMap<>();
private RestTemplate restTemplate = new RestTemplate();
@GetMapping({"/main"."/"})
@ResponseBody
public String main(a) {
User user = (User) RequestContextHolder.getRequestAttributes().getAttribute(CURRENT_USER, RequestAttributes.SCOPE_SESSION);
return "<html><body>hi:" + user.username + " This is Main</body></html>";
}
/** * Authorization redirect URL *@paramCode is used to get accessToken and can only be used once */
@GetMapping("/callback")
public String callback(@RequestParam(value = "code", required = false) String code,
RedirectAttributes redirectAttributes,
HttpServletRequest request, HttpServletResponse response) {
String referer = request.getParameter("referer");
String accessToken = getAccessToken(code, buildCallbackUrl(referer));
User user = getUser(accessToken);
String uuid = UUID.randomUUID().toString();
userStore.put(uuid, user);
//set cookie
response.addCookie(new Cookie(AUTHORIZATION_KEY, uuid));
return "redirect:" + referer;
}
private String buildCallbackUrl(String referer) {
return callbackUrl + "? referer=" + referer;
}
private User getUser(String accessToken) {
return restTemplate.getForObject(gitlabServerUrl + "/api/v4/user? access_token=" + accessToken, User.class);
}
/** * Get accessToken * from gitlab via code@param code
* @paramRedirectUri Callback address, which must be the same as the authorization parameter */
private String getAccessToken(String code, String redirectUri) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type"."authorization_code");
params.add("client_id", clientId);
params.add("client_secret", clientSecret);
params.add("code", code);
params.add("redirect_uri", redirectUri);
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(params, headers);
ResponseEntity<JSONAccessTokenResponse> response =
restTemplate.exchange(gitlabServerUrl + "/oauth/token",
HttpMethod.POST,
entity,
JSONAccessTokenResponse.class);
return Objects.requireNonNull(response.getBody()).access_token;
}
@Configuration
class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(
new HandlerInterceptorAdapter() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Optional<String> authorizationKeyOp = Arrays.stream(request.getCookies())
.filter(it->it.getName().equals(AUTHORIZATION_KEY))
.map(Cookie::getValue)
.findAny();
if (authorizationKeyOp.isPresent()) {
// The authorization information exists, and the user information is added to the session
RequestContextHolder.getRequestAttributes().setAttribute(CURRENT_USER, userStore.get(authorizationKeyOp.get()), RequestAttributes.SCOPE_SESSION);
return super.preHandle(request, response, handler);
} else {
// The authorization information does not exist, go to gitlab for verification
String referer = request.getRequestURL().toString();
String redirectUri = URLEncoder.encode(buildCallbackUrl(referer), "utf-8");
String gitlabAuthUrl = gitlabServerUrl + "/oauth/authorize? response_type=code&redirect_uri=" + redirectUri + "&client_id=" + clientId;
logger.info("gitlabAuthUrl:{}", gitlabAuthUrl);
response.sendRedirect(gitlabAuthUrl);
return false;
}
}
})
.addPathPatterns("/main"."/test"); }}static class JSONAccessTokenResponse implements Serializable {
public String access_token;
}
static class User implements Serializable {
public String name;
publicString username; }}Copy the code
New Gitlab applications
- Enter the name and Redirect URI in User Settings -> Applications, just check Confidential
- Click Save and record ClientId and Secret
The effect
- Browser to access http://localhost:9000/main
- Jump to
Gitlab
The login page
- Agree authorization (this action only needs to be done once)
- Automatic jump tohttp://localhost:9000/mainObtain the login account information
- Refresh the page to login state, no need to log in again. The login information is already in
Cookie
You do not need to log in again under the same domain name. - in
Gitlab Applications
You can view authorization status and cancel authorization
FAQs
- Gitlab error
The redirect url included is not valid
-> Confirm deliverycallback url
Path and parameters andapplications
Is filled in the same