Skip to content

Commit

Permalink
[Navidrome] Clean up base authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
Schaka committed Nov 7, 2024
1 parent c564c1b commit 0cde25b
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.github.schaka.naviseerr

import com.github.schaka.naviseerr.navidrome.NavidromeSessionUser
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
Expand All @@ -11,4 +13,10 @@ class LoginController {
fun showLogin(model: Model): String {
return "login"
}

@GetMapping("/dashboard")
fun showLogin(@AuthenticationPrincipal user: NavidromeSessionUser, model: Model): String {
model.addAttribute("user", user)
return "dashboard"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.github.schaka.naviseerr.config
import com.github.schaka.naviseerr.navidrome.NavidromeAuthenticationManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpStatus
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.web.SecurityFilterChain
Expand All @@ -20,19 +21,20 @@ class WebSecurityConfig(
.authenticationManager(authenticationManager)
.authorizeHttpRequests {
it
.requestMatchers("/login").permitAll()
.requestMatchers("/**").authenticated()
.requestMatchers("/login", "/login-error").permitAll()
.anyRequest().authenticated()
}
.formLogin {
it
.loginPage("/login")
.loginProcessingUrl("/login")
.failureUrl("/login-error")
.defaultSuccessUrl("/dashboard", true)
.permitAll()
}
.logout {
it
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.permitAll()
}
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package com.github.schaka.naviseerr.navidrome
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.stereotype.Component

@Component
Expand All @@ -19,12 +21,25 @@ class NavidromeAuthenticationManager(
)

try {
val client = newNavidromeClient(userProperties, objectMapper)
val user = client.listUsers()
val client = loginToNavidrome(userProperties).body!!
var roles = mutableListOf(SimpleGrantedAuthority("ROLE_USER"))
if (client.isAdmin) {
roles.add(SimpleGrantedAuthority("ROLE_ADMIN"))
}
val userClient = newNavidromeClient(userProperties, objectMapper)
val principal = NavidromeSessionUser(
client.id,
client.username,
userClient,
client.name,
client.lastFMApiKey
)

return UsernamePasswordAuthenticationToken(principal, "hidden-password", roles)
} catch (e: Exception) {
throw BadCredentialsException("Couldn't log in to navidrome client", e)
}

return authentication
throw BadCredentialsException("Couldn't log in to navidrome client")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,14 @@ package com.github.schaka.naviseerr.navidrome

import com.fasterxml.jackson.databind.ObjectMapper
import com.github.schaka.naviseerr.mediaserver.NavidromeClient
import com.github.schaka.naviseerr.navidrome.NavidromeClientConfig.NavidromeUserInterceptor
import feign.Feign
import feign.RequestInterceptor
import feign.RequestTemplate
import feign.jackson.JacksonDecoder
import feign.jackson.JacksonEncoder
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpHeaders.CONTENT_TYPE
import org.springframework.http.HttpMethod
import org.springframework.http.MediaType.APPLICATION_JSON_VALUE
import org.springframework.http.ResponseEntity
import org.springframework.web.client.RestTemplate
import java.time.LocalDateTime

@Configuration(proxyBeanMethods = false)
Expand All @@ -44,7 +36,7 @@ class NavidromeClientConfig {

if (lastUpdate.plusMinutes(30).isBefore(LocalDateTime.now())) {
val userInfo = getUserInfo(properties)
accessToken = userInfo.body?.get("token").toString()
accessToken = userInfo.body?.token.toString()
lastUpdate = LocalDateTime.now()
log.info("Logged in to Navidrome as {} {}", properties.username, accessToken)
}
Expand All @@ -55,29 +47,10 @@ class NavidromeClientConfig {
template.header(CONTENT_TYPE, APPLICATION_JSON_VALUE)
}

private fun getUserInfo(properties: NavidromeProperties): ResponseEntity<Map<*, *>> {
val login = RestTemplate()
val headers = HttpHeaders()
headers.set(CONTENT_TYPE, APPLICATION_JSON_VALUE)

val loginInfo = """
{
"username": "${properties.username}",
"password": "${properties.password}"
}
""".trimIndent()

return login.exchange("${properties.url}/auth/login", HttpMethod.POST, HttpEntity(loginInfo, headers), Map::class.java)
private fun getUserInfo(properties: NavidromeProperties): ResponseEntity<NavidromeUserInfo> {
return loginToNavidrome(properties)
}

}

}

fun newNavidromeClient(properties: NavidromeProperties, mapper: ObjectMapper): NavidromeClient {
return Feign.builder()
.decoder(JacksonDecoder(mapper))
.encoder(JacksonEncoder(mapper))
.requestInterceptor(NavidromeUserInterceptor(properties))
.target(NavidromeClient::class.java, "${properties.url}/api")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.github.schaka.naviseerr.navidrome

import com.fasterxml.jackson.databind.ObjectMapper
import com.github.schaka.naviseerr.mediaserver.NavidromeClient
import com.github.schaka.naviseerr.navidrome.NavidromeClientConfig.NavidromeUserInterceptor
import feign.Feign
import feign.jackson.JacksonDecoder
import feign.jackson.JacksonEncoder
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpHeaders.CONTENT_TYPE
import org.springframework.http.HttpMethod
import org.springframework.http.MediaType.APPLICATION_JSON_VALUE
import org.springframework.http.ResponseEntity
import org.springframework.web.client.RestTemplate

data class NavidromeUserInfo(
val id: String,
val isAdmin: Boolean,
val lastFMApiKey: String,
val name: String,
val subsonicSalt: String,
val subsonicToken: String,
val token: String,
val username: String,
)

data class NavidromeSessionUser(
val id: String,
val username: String,
val restClient: NavidromeClient,

val name: String,
val lastFMApiKey: String,
)

fun loginToNavidrome(properties: NavidromeProperties): ResponseEntity<NavidromeUserInfo> {
val login = RestTemplate()
val headers = HttpHeaders()
headers.set(CONTENT_TYPE, APPLICATION_JSON_VALUE)

val loginInfo = """
{
"username": "${properties.username}",
"password": "${properties.password}"
}
""".trimIndent()

return login.exchange("${properties.url}/auth/login", HttpMethod.POST, HttpEntity(loginInfo, headers), NavidromeUserInfo::class.java)
}

fun newNavidromeClient(properties: NavidromeProperties, mapper: ObjectMapper): NavidromeClient {
return Feign.builder()
.decoder(JacksonDecoder(mapper))
.encoder(JacksonEncoder(mapper))
.requestInterceptor(NavidromeUserInterceptor(properties))
.target(NavidromeClient::class.java, "${properties.url}/api")
}
5 changes: 5 additions & 0 deletions src/main/resources/templates/dashboard.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html lang="en">
<body>
<p th:text="'Welcome ' + ${user.username} + '!'">Welcome, logged in user!</p>
</body>
</html>

0 comments on commit 0cde25b

Please sign in to comment.