mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-02-17 15:01:42 +08:00
fix: only allow relative urls in redirects
This commit is contained in:
parent
1f46cbf4b1
commit
c4585f7e41
@ -17,6 +17,8 @@ import io.papermc.hangar.service.ValidationService;
|
|||||||
import io.papermc.hangar.service.internal.auth.SSOService;
|
import io.papermc.hangar.service.internal.auth.SSOService;
|
||||||
import jakarta.servlet.http.Cookie;
|
import jakarta.servlet.http.Cookie;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@ -51,9 +53,9 @@ public class LoginController extends HangarComponent {
|
|||||||
|
|
||||||
final UserTable fakeUser = this.authenticationService.loginAsFakeUser();
|
final UserTable fakeUser = this.authenticationService.loginAsFakeUser();
|
||||||
this.tokenService.issueRefreshToken(fakeUser);
|
this.tokenService.issueRefreshToken(fakeUser);
|
||||||
return this.addBaseAndRedirect(returnUrl);
|
return this.addBaseAndRedirect(this.cutoffAbsoluteUrls(returnUrl));
|
||||||
} else {
|
} else {
|
||||||
this.response.addCookie(new Cookie("url", returnUrl));
|
this.response.addCookie(new Cookie("url", this.cutoffAbsoluteUrls(returnUrl)));
|
||||||
return this.redirectToSso(this.ssoService.getLoginUrl(this.config.getBaseUrl() + "/login"));
|
return this.redirectToSso(this.ssoService.getLoginUrl(this.config.getBaseUrl() + "/login"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +72,18 @@ public class LoginController extends HangarComponent {
|
|||||||
throw new HangarApiException("nav.user.error.invalidUsername");
|
throw new HangarApiException("nav.user.error.invalidUsername");
|
||||||
}
|
}
|
||||||
this.tokenService.issueRefreshToken(user);
|
this.tokenService.issueRefreshToken(user);
|
||||||
return this.addBaseAndRedirect(url);
|
return this.addBaseAndRedirect(this.cutoffAbsoluteUrls(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cutoffAbsoluteUrls(final String url) {
|
||||||
|
try {
|
||||||
|
if (!new URI(url).isAbsolute()) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
} catch (final URISyntaxException ignored) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
return "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ -93,16 +106,16 @@ public class LoginController extends HangarComponent {
|
|||||||
@GetMapping(path = "/logout", params = "returnUrl")
|
@GetMapping(path = "/logout", params = "returnUrl")
|
||||||
public String logout(@RequestParam(defaultValue = "/?loggedOut") final String returnUrl) {
|
public String logout(@RequestParam(defaultValue = "/?loggedOut") final String returnUrl) {
|
||||||
if (this.config.fakeUser.enabled()) {
|
if (this.config.fakeUser.enabled()) {
|
||||||
this.response.addCookie(new Cookie("url", returnUrl));
|
this.response.addCookie(new Cookie("url", this.cutoffAbsoluteUrls(returnUrl)));
|
||||||
return "/fake-logout";
|
return "/fake-logout";
|
||||||
} else {
|
} else {
|
||||||
this.response.addCookie(new Cookie("url", returnUrl));
|
this.response.addCookie(new Cookie("url", this.cutoffAbsoluteUrls(returnUrl)));
|
||||||
final Optional<HangarPrincipal> principal = this.getOptionalHangarPrincipal();
|
final Optional<HangarPrincipal> principal = this.getOptionalHangarPrincipal();
|
||||||
if (principal.isPresent()) {
|
if (principal.isPresent()) {
|
||||||
return this.ssoService.getLogoutUrl(this.config.getBaseUrl() + "/handle-logout", principal.get()).url();
|
return this.ssoService.getLogoutUrl(this.config.getBaseUrl() + "/handle-logout", principal.get()).url();
|
||||||
} else {
|
} else {
|
||||||
this.tokenService.invalidateToken(null);
|
this.tokenService.invalidateToken(null);
|
||||||
return this.addBase(returnUrl);
|
return this.addBase(this.cutoffAbsoluteUrls(returnUrl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +131,7 @@ public class LoginController extends HangarComponent {
|
|||||||
if (session != null) {
|
if (session != null) {
|
||||||
session.invalidate();
|
session.invalidate();
|
||||||
}
|
}
|
||||||
return this.addBaseAndRedirect(returnUrl);
|
return this.addBaseAndRedirect(this.cutoffAbsoluteUrls(returnUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(path = "/handle-logout", params = "state")
|
@GetMapping(path = "/handle-logout", params = "state")
|
||||||
@ -143,7 +156,7 @@ public class LoginController extends HangarComponent {
|
|||||||
if (session != null) {
|
if (session != null) {
|
||||||
session.invalidate();
|
session.invalidate();
|
||||||
}
|
}
|
||||||
return this.addBaseAndRedirect(returnUrl);
|
return this.addBaseAndRedirect(this.cutoffAbsoluteUrls(returnUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/signup")
|
@GetMapping("/signup")
|
||||||
@ -151,7 +164,7 @@ public class LoginController extends HangarComponent {
|
|||||||
if (this.config.fakeUser.enabled()) {
|
if (this.config.fakeUser.enabled()) {
|
||||||
throw new HangarApiException("nav.user.error.fakeUserEnabled", "Signup");
|
throw new HangarApiException("nav.user.error.fakeUserEnabled", "Signup");
|
||||||
}
|
}
|
||||||
return new RedirectView(this.ssoService.getSignupUrl(returnUrl));
|
return new RedirectView(this.ssoService.getSignupUrl(this.cutoffAbsoluteUrls(returnUrl)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/sync")
|
@PostMapping("/sync")
|
||||||
|
@ -5,7 +5,6 @@ import { useAuthStore } from "~/store/auth";
|
|||||||
import { useCookies } from "~/composables/useCookies";
|
import { useCookies } from "~/composables/useCookies";
|
||||||
import { useInternalApi } from "~/composables/useApi";
|
import { useInternalApi } from "~/composables/useApi";
|
||||||
import { authLog } from "~/lib/composables/useLog";
|
import { authLog } from "~/lib/composables/useLog";
|
||||||
import { useConfig } from "~/lib/composables/useConfig";
|
|
||||||
import { handleRequestError, useRequestEvent } from "#imports";
|
import { handleRequestError, useRequestEvent } from "#imports";
|
||||||
import { useAxios } from "~/composables/useAxios";
|
import { useAxios } from "~/composables/useAxios";
|
||||||
import { useNotificationStore } from "~/lib/store/notification";
|
import { useNotificationStore } from "~/lib/store/notification";
|
||||||
@ -16,12 +15,12 @@ class Auth {
|
|||||||
if (redirectUrl.endsWith("?loggedOut")) {
|
if (redirectUrl.endsWith("?loggedOut")) {
|
||||||
redirectUrl = redirectUrl.replace("?loggedOut", "");
|
redirectUrl = redirectUrl.replace("?loggedOut", "");
|
||||||
}
|
}
|
||||||
return `/login?returnUrl=${useConfig().publicHost}${redirectUrl}`;
|
return `/login?returnUrl=${redirectUrl}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async logout() {
|
async logout() {
|
||||||
const result = await useAxios()
|
const result = await useAxios()
|
||||||
.get(`/logout?returnUrl=${useConfig().publicHost}?loggedOut`)
|
.get(`/logout?returnUrl=/?loggedOut`)
|
||||||
.catch((e) => handleRequestError(e));
|
.catch((e) => handleRequestError(e));
|
||||||
if (result?.status === 200 && result?.data) {
|
if (result?.status === 200 && result?.data) {
|
||||||
location.replace(result?.data);
|
location.replace(result?.data);
|
||||||
|
Loading…
Reference in New Issue
Block a user