mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Fix SSO logout (#715)
This commit is contained in:
@@ -2,7 +2,6 @@ import {useAuth} from "Frontend/util/auth";
|
|||||||
import {GearFine, Question, SignOut, User} from "@phosphor-icons/react";
|
import {GearFine, Question, SignOut, User} from "@phosphor-icons/react";
|
||||||
import {Dropdown, DropdownItem, DropdownMenu, DropdownTrigger} from "@heroui/react";
|
import {Dropdown, DropdownItem, DropdownMenu, DropdownTrigger} from "@heroui/react";
|
||||||
import {useNavigate} from "react-router";
|
import {useNavigate} from "react-router";
|
||||||
import {ConfigEndpoint} from "Frontend/generated/endpoints";
|
|
||||||
import Avatar from "Frontend/components/general/Avatar";
|
import Avatar from "Frontend/components/general/Avatar";
|
||||||
import {CollectionElement} from "@react-types/shared";
|
import {CollectionElement} from "@react-types/shared";
|
||||||
import {isAdmin} from "Frontend/util/utils";
|
import {isAdmin} from "Frontend/util/utils";
|
||||||
@@ -11,14 +10,6 @@ export default function ProfileMenu() {
|
|||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
async function logout() {
|
|
||||||
if (auth.state.user?.managedBySso) {
|
|
||||||
window.location.href = (await ConfigEndpoint.getSsoLogoutUrl()) || "/";
|
|
||||||
} else {
|
|
||||||
await auth.logout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const profileMenuItems = [
|
const profileMenuItems = [
|
||||||
{
|
{
|
||||||
label: "My Profile",
|
label: "My Profile",
|
||||||
@@ -39,7 +30,7 @@ export default function ProfileMenu() {
|
|||||||
{
|
{
|
||||||
label: "Sign Out",
|
label: "Sign Out",
|
||||||
icon: <SignOut/>,
|
icon: <SignOut/>,
|
||||||
onClick: logout,
|
onClick: auth.logout,
|
||||||
color: "primary"
|
color: "primary"
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,60 +1,69 @@
|
|||||||
package org.gameyfin.app.core.security
|
package org.gameyfin.app.core.security
|
||||||
|
|
||||||
import com.vaadin.flow.spring.security.VaadinWebSecurity
|
import com.vaadin.flow.spring.security.VaadinAwareSecurityContextHolderStrategyConfiguration
|
||||||
|
import com.vaadin.flow.spring.security.VaadinSecurityConfigurer
|
||||||
|
import com.vaadin.hilla.route.RouteUtil
|
||||||
import org.gameyfin.app.config.ConfigProperties
|
import org.gameyfin.app.config.ConfigProperties
|
||||||
import org.gameyfin.app.config.ConfigService
|
import org.gameyfin.app.config.ConfigService
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Conditional
|
import org.springframework.context.annotation.Conditional
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.context.annotation.Import
|
||||||
import org.springframework.core.env.Environment
|
import org.springframework.core.env.Environment
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy
|
import org.springframework.security.config.http.SessionCreationPolicy
|
||||||
import org.springframework.security.core.session.SessionRegistry
|
import org.springframework.security.core.session.SessionRegistry
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration
|
import org.springframework.security.oauth2.client.registration.ClientRegistration
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository
|
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType
|
import org.springframework.security.oauth2.core.AuthorizationGrantType
|
||||||
|
import org.springframework.security.web.SecurityFilterChain
|
||||||
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler
|
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
|
@Import(
|
||||||
|
VaadinAwareSecurityContextHolderStrategyConfiguration::class
|
||||||
|
)
|
||||||
class SecurityConfig(
|
class SecurityConfig(
|
||||||
private val environment: Environment,
|
private val environment: Environment,
|
||||||
private val config: ConfigService,
|
private val config: ConfigService,
|
||||||
private val ssoAuthenticationSuccessHandler: SsoAuthenticationSuccessHandler,
|
private val ssoAuthenticationSuccessHandler: SsoAuthenticationSuccessHandler,
|
||||||
private val sessionRegistry: SessionRegistry
|
private val sessionRegistry: SessionRegistry
|
||||||
) : VaadinWebSecurity() {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val SSO_PROVIDER_KEY = "oidc"
|
const val SSO_PROVIDER_KEY = "oidc"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Bean
|
||||||
override fun configure(http: HttpSecurity) {
|
fun filterChain(http: HttpSecurity, routeUtil: RouteUtil): SecurityFilterChain {
|
||||||
|
http.authorizeHttpRequests { auth ->
|
||||||
// Configure your static resources with public access before calling super.configure(HttpSecurity) as it adds final anyRequest matcher
|
// Set default security policy that permits Hilla internal requests and denies all other
|
||||||
http.authorizeHttpRequests { auth: AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry ->
|
auth.requestMatchers(routeUtil::isRouteAllowed).permitAll()
|
||||||
auth.requestMatchers("/login").permitAll()
|
// Gameyfin static resources and public endpoints
|
||||||
.requestMatchers("/setup").permitAll()
|
.requestMatchers(
|
||||||
.requestMatchers("/reset-password").permitAll()
|
"/login",
|
||||||
.requestMatchers("/accept-invitation").permitAll()
|
"/setup",
|
||||||
.requestMatchers("/public/**").permitAll()
|
"/reset-password",
|
||||||
.requestMatchers("/images/**").permitAll()
|
"/accept-invitation",
|
||||||
.requestMatchers("/favicon.ico").permitAll()
|
"/public/**",
|
||||||
.requestMatchers("/favicon.svg").permitAll()
|
"/images/**",
|
||||||
|
"/favicon.ico",
|
||||||
// Dynamic public access for certain endpoints
|
"/favicon.svg"
|
||||||
auth.requestMatchers("/").access(DynamicPublicAccessAuthorizationManager(config))
|
).permitAll()
|
||||||
.requestMatchers("/game/**").access(DynamicPublicAccessAuthorizationManager(config))
|
// Dynamic public access for certain endpoints
|
||||||
.requestMatchers("/library/**").access(DynamicPublicAccessAuthorizationManager(config))
|
.requestMatchers(
|
||||||
.requestMatchers("/search/**").access(DynamicPublicAccessAuthorizationManager(config))
|
"/",
|
||||||
.requestMatchers("/requests/**").access(DynamicPublicAccessAuthorizationManager(config))
|
"/game/**",
|
||||||
.requestMatchers("/download/**").access(DynamicPublicAccessAuthorizationManager(config))
|
"/library/**",
|
||||||
|
"/search/**",
|
||||||
|
"/requests/**",
|
||||||
|
"/download/**"
|
||||||
|
).access(DynamicPublicAccessAuthorizationManager(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
http.sessionManagement { sessionManagement ->
|
http.sessionManagement { sessionManagement ->
|
||||||
@@ -67,11 +76,14 @@ class SecurityConfig(
|
|||||||
// Not needed since the frontend is served by the backend
|
// Not needed since the frontend is served by the backend
|
||||||
http.cors { cors -> cors.disable() }
|
http.cors { cors -> cors.disable() }
|
||||||
|
|
||||||
super.configure(http)
|
|
||||||
|
|
||||||
setLoginView(http, "/login", "/")
|
|
||||||
|
|
||||||
if (config.get(ConfigProperties.SSO.OIDC.Enabled) == true) {
|
if (config.get(ConfigProperties.SSO.OIDC.Enabled) == true) {
|
||||||
|
|
||||||
|
http.with(VaadinSecurityConfigurer.vaadin()) { configurer ->
|
||||||
|
// Redirect to SSO provider on logout
|
||||||
|
configurer.loginView("/login", config.get(ConfigProperties.SSO.OIDC.LogoutUrl))
|
||||||
|
}
|
||||||
|
|
||||||
// Use custom success handler to handle user registration
|
// Use custom success handler to handle user registration
|
||||||
http.oauth2Login { oauth2Login -> oauth2Login.successHandler(ssoAuthenticationSuccessHandler) }
|
http.oauth2Login { oauth2Login -> oauth2Login.successHandler(ssoAuthenticationSuccessHandler) }
|
||||||
// Prevent unnecessary redirects
|
// Prevent unnecessary redirects
|
||||||
@@ -81,16 +93,18 @@ class SecurityConfig(
|
|||||||
http.exceptionHandling { exceptionHandling ->
|
http.exceptionHandling { exceptionHandling ->
|
||||||
exceptionHandling.authenticationEntryPoint(CustomAuthenticationEntryPoint())
|
exceptionHandling.authenticationEntryPoint(CustomAuthenticationEntryPoint())
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Use default Vaadin login URLs
|
||||||
|
http.with(VaadinSecurityConfigurer.vaadin()) { configurer ->
|
||||||
|
configurer.loginView("/login")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
public override fun configure(web: WebSecurity) {
|
|
||||||
super.configure(web)
|
|
||||||
|
|
||||||
if ("dev" in environment.activeProfiles) {
|
if ("dev" in environment.activeProfiles) {
|
||||||
web.ignoring().requestMatchers("/h2-console/**")
|
http.authorizeHttpRequests { auth -> auth.requestMatchers("/h2-console/**").permitAll() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return http.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
+5
-5
@@ -3,12 +3,12 @@ org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m
|
|||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
# Plugin versions
|
# Plugin versions
|
||||||
kotlinVersion=2.2.0
|
kotlinVersion=2.2.20
|
||||||
kspVersion=2.2.0-2.0.2
|
kspVersion=2.2.20-2.0.3
|
||||||
vaadinVersion=24.8.7
|
vaadinVersion=24.9.0
|
||||||
springBootVersion=3.5.3
|
springBootVersion=3.5.6
|
||||||
springCloudVersion=2025.0.0
|
springCloudVersion=2025.0.0
|
||||||
springDependencyManagementVersion=1.1.7
|
springDependencyManagementVersion=1.1.7
|
||||||
# Dependency versions
|
# Dependency versions
|
||||||
pf4jVersion=3.13.0
|
pf4jVersion=3.13.0
|
||||||
pf4jKspVersion=2.2.0-1.0.3
|
pf4jKspVersion=2.2.20-1.0.3
|
||||||
Reference in New Issue
Block a user