Query a password protected WebService in Spring-Boot via HealthIndicator - spring-boot

I need to query a WebService and check its results to calculate a Health.status() in SpringBoot.
Health is then used for k8s in its liveness probe: /actuator/health.
However, the WebService that I need to query needs a username and password, whereas the endpoint itself does not, as it is consumed by k8s and Prometheus. Please see the following configuration:
http
.authorizeRequests()
.requestMatchers(EndpointRequest.to("info", "health")).permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.sessionManagement().sessionCreationPolicy(STATELESS)
.and()
.csrf().disable()
As the WebService in question can be queried when httpBasic() is used to authenticate, I need to somehow use basic authentication in HealthIndicator without passing these values in the request.
What I want to do is to have "health" permitted for unauthorised requests, but still transparently authenticate with a technical user to query a third party service. Please see comment in following snippet:
override fun health(): Health {
val status = Health.up()
val beforeServiceCall = System.nanoTime()
val partner =
try {
// COMMENT FOR StackOverflow
// this call here needs authentication resp. a token which is only generated when basicAuth is used
partnerService.getPartner(
process = metricsProperties.process,
partnerNumber = metricsProperties.partnernumber
)
} catch (e: Exception) {
null
}
val afterServiceCall = System.nanoTime()
return status
.withDetail(PARTNER_FOUND, partner.let {
if (it != null) {
1.0
} else {
status.unknown()
0.0
}
})
.withDetail(PARTNER_QUERY_TIME_MS, ((afterServiceCall - beforeServiceCall) / 1e6).toDouble())
.build()
tl;dr;
I need to somehow trigger the WebSecurityConfigurerAdapter's configure method from within my HealthIndicator to obtain a valid token to be able to query a third party service. How can this configure method be triggered explicitly?
#Configuration
#EnableWebSecurity
class SecurityConfig(omitted params) :
WebSecurityConfigurerAdapter() {
override fun configure(auth: AuthenticationManagerBuilder) {
auth
.authenticationProvider(object : AuthenticationProvider {
override fun authenticate(authentication: Authentication): Authentication? {
val authorizationGrant = ResourceOwnerPasswordCredentialsGrant(authentication.name,
Secret(authentication.credentials as String))
val tokenRequest = TokenRequest(URI(keycloakUrl),
ClientID(clientID),
authorizationGrant)
val tokenResponse = TokenResponse
.parse(tokenRequest
.toHTTPRequest()
.send())
if (tokenResponse.indicatesSuccess()) {
return UsernamePasswordAuthenticationToken(
authentication.name,
null,
emptyList())
} else {
throw BadCredentialsException("Error logging in")
}
}
override fun supports(authentication: Class<*>): Boolean {
return authentication == UsernamePasswordAuthenticationToken::class.java
}
})
.eraseCredentials(false)
}

Related

Websocket request not routed through gateway global filter

Problem
I have setup a global filter for all requests that adds user information to the headers. This filter works for all my http requests but doesnt apply them to my websocket requests.
Questions
Do websocket requests got through GlobalFilters?
If websocket requests do not go through GlobalFilters is there a way to specify a filter for websockets?
Are there any approaches that will allow me to inject user info into the websocket requests via spring-cloud-gateway?
Setup
Gateway configuration
gateway:
routes:
- id: example
uri: http://localhost:80
predicates:
- Path=/example/**
filters:
- RewritePath=/example/(?<path>.*), /$\{path}
GloablFilter
#Component
class CustomGlobalFilter(private val jwtDecoder: ReactiveJwtDecoder) : GlobalFilter {
private val logger = KotlinLogging.logger {}
/**
* Given exchange, extract Authorization header value and modify to retrieve JWT token.
*/
fun extractJwtToken(exchange: ServerWebExchange): String {
return (exchange.request.headers["Authorization"]
?: throw JwtExtractionException("Request does not contain Authorization header"))[0]
.replace("Bearer ", "")
}
/**
* Modify request headers to add `username`.
*/
fun modifyHeaders(exchange: ServerWebExchange): Mono<ServerWebExchange> {
return try {
val jwt = extractJwtToken(exchange)
jwtDecoder
.decode(jwt)
.map {
val username = it.claims["username"] as String
val modRequest = exchange
.request
.mutate()
.header("username", username)
.build()
exchange.mutate()
.request(modRequest)
.build()
}
} catch (e: JwtExtractionException) {
exchange.toMono() // fall back on default exchange
}
}
/**
* Filter all outgoing requests to modify headers.
*/
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
return modifyHeaders(exchange)
.flatMap { chain.filter(it) }
}
}
I was able to fix the routing issue by setting the custom filter order before the WebsocketRoutingFilter
#Component
class CustomGlobalFilter(
private val authFilterUtil: AuthFilterUtil,
) : GlobalFilter, Ordered {
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
return authFilterUtil
.modifyHeaders(exchange)
.flatMap { chain.filter(it) }
}
override fun getOrder(): Int {
return Ordered.HIGHEST_PRECEDENCE
}
}

How to handle login failure with Spring API on server and Retrofit2 on Android?

On server side I have created simple Spring API with authentication. I have just added implementation("org.springframework.boot:spring-boot-starter-security") dependency and when I go to url with browser - it shows login page when I'm not logged in.
For now I'm using basic authentication, my username and password set in configuration file like this (resources/application.properties file):
spring.security.user.name=myusername
spring.security.user.password=mypassword
spring.security.user.roles=manager
I'm also using Spring Data REST, so Spring creates API automatically for JPA repositories that exist in my project. I had to set up my database, create JPA repositories for tables and add implementation("org.springframework.boot:spring-boot-starter-data-rest") to my dependencies to make it work.
On Android side I call my API with this Adapter and Client.
interface ApiClient {
#GET("inventoryItems/1")
suspend fun getFirstInventoryItem(): Response<InventoryItemDto>
}
object ApiAdapter {
private const val API_BASE_URL = "http://some.url/"
private const val API_USERNAME = "myusername"
private const val API_PASSWORD = "mypassword"
val apiClient: ApiClient = Retrofit.Builder()
.baseUrl(API_BASE_URL)
.client(getHttpClient(API_USERNAME, API_PASSWORD))
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiClient::class.java)
private fun getHttpClient(user: String, pass: String): OkHttpClient =
OkHttpClient
.Builder()
.authenticator(getBasicAuth(user,pass))
.build()
private fun getBasicAuth(username: String?, password: String?): Authenticator? =
object : Authenticator {
override fun authenticate(route: Route?, response: okhttp3.Response): Request? {
return response
.request()
.newBuilder()
.addHeader("Authorization", Credentials.basic(username, password))
.build()
}
}
}
And this is how I call my API on Android:
(I'm calling this from onViewCreated on my view Fragment)
lifecycleScope.launch {
val item: InventoryItemDto? = ApiAdapter.apiClient.getFirstInventoryItem().body()
binding?.tvTest?.text = item.toString()
}
When I provide correct password everything works.
But when I provide wrong password my Android app crashes because java.net.ProtocolException: Too many follow-up requests: 21 is thrown.
It looks like my Android client goes to requested url (inventoryItems/1) and then it is redirected to login page. Then my clients tries to authenticate on that page again, because I have .addHeader("Authorization", Credentials.basic(username, password)) added to every request (I assume). Login is failed again, so it is redirected again to login page where it sends wrong credentials again and again is redirected...
My question 1: how to deal with login failed properly on Android and/or Spring?
My question 2: how to handle other errors (like bad request) properly on Android and/or Spring?
What I have tried:
Disable followRedirects and followSslRedirects on Android side like this:
private fun getHttpClient(user: String, pass: String): OkHttpClient =
OkHttpClient
.Builder()
.followRedirects(false)
.followSslRedirects(talse)
.authenticator(getBasicAuth(user,pass))
.build()
Add .addHeader("X-Requested-With", "XMLHttpRequest") header, also on Android side:
private fun getBasicAuth(username: String?, password: String?):Authenticator? =
object : Authenticator {
override fun authenticate(route: Route?, response: okhttp3.Response): Request? {
return response
.request()
.newBuilder()
.addHeader("Authorization", Credentials.basic(username, password))
.addHeader("X-Requested-With", "XMLHttpRequest")
.build()
}
}
OK, I got this (answering my own question). Solution is based on this: link
I will not accept my answer, maybe someone will propose some solution without deprecated class, and maybe with good explanation.
I have created my own AuthenticationFailureHandler, like this:
class CustomAuthenticationFailureHandler : AuthenticationFailureHandler {
private val objectMapper = ObjectMapper()
#Throws(IOException::class, ServletException::class)
override fun onAuthenticationFailure(
request: HttpServletRequest?,
response: HttpServletResponse,
exception: AuthenticationException
) {
response.status = HttpStatus.UNAUTHORIZED.value()
val data: MutableMap<String, Any> = HashMap()
data["timestamp"] = Calendar.getInstance().time
data["exception"] = exception.message.toString()
response.outputStream.println(objectMapper.writeValueAsString(data))
}
}
I had to configure security manually by creating this class:
#Configuration
#EnableWebSecurity
class SecurityConfiguration : WebSecurityConfigurerAdapter() {
#Throws(Exception::class)
override fun configure(auth: AuthenticationManagerBuilder) {
auth.inMemoryAuthentication()
.withUser(API_USERNAME)
.password(passwordEncoder().encode(API_PASSWORD))
.roles(API_ROLE)
}
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http
.authorizeRequests()
.anyRequest()
.authenticated()
}
#Bean
fun authenticationFailureHandler(): AuthenticationFailureHandler = CustomAuthenticationFailureHandler()
#Bean
fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder()
companion object {
private const val API_USERNAME = "user1"
private const val API_PASSWORD = "user1"
private const val API_ROLE = "USER"
}
}
Unfortunately WebSecurityConfigurerAdapter class is deprected. I will deal with that later.

Kotlin Spring Session concurrent session control on already defined Security config

This is a repost from the Github issues page.
Confused on why there are no behavior changes when adding the concurrency session control with Spring session with this documentation
Versions:
Spring Security 5.2.1.RELEASE
Spring Session-JDBC 2.2.0.RELEASE
Spring Boot 2.2.4.RELEASE
Code snippets from our code:
SecurityConfig.kt
#EnableWebSecurity
#Profile("auth")
#Configuration
class SecurityConfig<S: Session> : WebSecurityConfigurerAdapter() {
//<some-code-here>
#Autowired
private lateinit var sessionRepository: FindByIndexNameSessionRepository<S>
override fun configure(http: HttpSecurity) {
/*
TODO enforce requiring application/json content type everywhere (apparently except file upload)
*/
val publicPaths = arrayOf(
"/api/v1/centralPortal/current/forgot-password",
"/api/v1/centralPortal/current/reset-password/*",
"/api/v1/centralPortal/current/onboard/*",
"/login",
"/api/v1/public/**" // CSP reporting is there, needs CSRF disabled
)
val filter = JsonLoginFilter(objectMapper, audit, rateLimiter, userManagementService, getAuthMode(env))
filter.rateLimitPPS = rateLimitPermits / rateLimitSeconds
filter.setSessionAuthenticationStrategy(sas)
filter.setAuthenticationManager(authenticationManager())
filter.setAuthenticationSuccessHandler { request, response, _ ->
val csrfToken = request.getAttribute(CsrfToken::class.java.name) as CsrfToken
response.addHeader(csrfToken.headerName, csrfToken.token)
}
filter.setAuthenticationFailureHandler { request, response, exception ->
excHandlerAdvice.handleUnauthenticated(request, response, exception, filter.obtainRetries()) }
http
.cors().and()
.httpBasic().disable()
.formLogin().disable()
.rememberMe().disable()
.headers()
// do custom handling of the X-Frame-Options header because some pages need to be iframed
.frameOptions().disable()
.addHeaderWriter(ConfigurableFrameOptionsHeaderWriter("/assets/pdfjs/web/viewer.html", "/ws/frame.html"))
.and()
.csrf()
.ignoringAntMatchers(*publicPaths)
.and()
.authorizeRequests()
.antMatchers("/manifest.json", "/manifest.webmanifest").permitAll()
.antMatchers("/", "/index.js", "/main.js", "/vendor.js", "/service-worker.js", "/workbox-v*/workbox-sw.js", "/precache.*.js", "/*.ico", "/ui/**", "/index.html").permitAll()
.regexMatchers("^/\\w\\w/ui/.*$").permitAll()
.antMatchers("/assets/**/*.webp", "/assets/**/*.png", "/assets/**/*.jpg", "/assets/**/*.svg", "/assets/**/*.gif").permitAll()
.antMatchers("/assets/**/*.woff", "/assets/**/*.woff2", "/assets/**/*.ttf", "/assets/**/*.eot").permitAll()
.antMatchers("/assets/**/*.css").permitAll()
.antMatchers(*publicPaths).permitAll()
.antMatchers("/img/logo.png").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.accessDeniedHandler { request, response, accessDeniedException -> excHandlerAdvice.handleAccessDenied(request, response, accessDeniedException) }
.authenticationEntryPoint { request, response, authException -> excHandlerAdvice.handleUnauthenticated(request, response, authException) }
.and()
.addFilter(filter)
.logout()
.logoutSuccessHandler { request, response, auth -> Unit } // don't redirect
.and()
http.headers()
.cacheControl().disable()
.addHeaderWriter(CacheControlWriterWithWorkaround())
// Concurrency control code
http.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry())
}
private fun sessionRegistry(): SpringSessionBackedSessionRegistry<S> {
return SpringSessionBackedSessionRegistry(this.sessionRepository)
}
}
JsonLoginFilter.kt
data class UserLogin(val username: String, val password: String)
class JsonLoginFilter(private val objectMapper: ObjectMapper, val audit: AuditService?, val rateLimiter: RateLimiterAspect, val userManagementService: UserManagementService?, val authMode: AuthMode) : UsernamePasswordAuthenticationFilter() {
var rateLimitPPS: Double = 1 / 2.0 // rate limiter permits per second default value
private var _parsed: UserLogin? = null
private val log = loggerFor<JsonLoginFilter>()
fun parsedLogin(request: HttpServletRequest): UserLogin {
val body = request.inputStream
return objectMapper.readValue(body, UserLogin::class.java)
}
private fun loginAttempt(success: Boolean) {
log.info("Login attempt username=${_parsed?.username} success=$success")
if (success) {
resetRetries()
}
audit?.eventWithPrincipal(
AuditObjectCategory.USERS,
"User",
_parsed?.username,
if (success) OtherActions.USER_LOGIN else OtherActions.USER_LOGIN_FAIL,
_parsed?.username
)
}
override fun attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse?): Authentication {
try {
rateLimiter.rateLimit(request, "login", rateLimitPPS)
_parsed = parsedLogin(request)
val authResult = super.attemptAuthentication(request, response)
loginAttempt(authResult != null)
return authResult
} catch (e: RateLimiterException) {
throw e
} catch (ex: AuthenticationException) {
loginAttempt(false)
if (authMode == AuthMode.BUILTIN) userManagementService?.checkUserRetries(_parsed!!.username)
throw ex
}
}
fun obtainRetries(): Int? {
return if (authMode == AuthMode.BUILTIN) userManagementService?.getUserRetries(_parsed!!.username) else 0
}
fun resetRetries() {
if (authMode == AuthMode.BUILTIN) {
userManagementService?.resetUserRetries(_parsed!!.username)
}
}
override fun obtainPassword(request: HttpServletRequest): String {
return _parsed!!.password
}
override fun obtainUsername(request: HttpServletRequest): String {
return _parsed!!.username
}
}
spring.session.store-type=jdbc
So my expected behavior based on the code and the documentation would be when there is current login user then another user logs in into another browser, it should prevent the login with maxSessionPreventsLogin(true).
So the actual behavior on the code above is that 2 browser with the same user can login, which I didn't expect, since I followed the docs. I'm not really sure if I am missing something, as this is my first time I am encountering Spring Session and Spring Security. Please also take note that the sessions are stored in a DB rather than in-memory.
I would really love if someone can point me to the steps of the correct Spring session configuration, or maybe the documentation should have a precursor on what to configure before doing this, or what when is not an applicable approach.
Thanks

Webflux JWT Authorization not working fine

I am following a tutorial about JWT in a spring reactive context (webflux).
The token generation is working fine, however the authorization is not working when I use the Authorization with bearer
Here is what I have done:
#EnableWebFluxSecurity
#EnableReactiveMethodSecurity
public class WebSecurityConfig{
#Autowired private JWTReactiveAuthenticationManager authenticationManager;
#Autowired private SecurityContextRepository securityContext;
#Bean public SecurityWebFilterChain configure(ServerHttpSecurity http){
return http.exceptionHandling()
.authenticationEntryPoint((swe , e) -> {
return Mono.fromRunnable(()->{
System.out.println( "authenticationEntryPoint user trying to access unauthorized api end points : "+
swe.getRequest().getRemoteAddress()+
" in "+swe.getRequest().getPath());
swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
});
}).accessDeniedHandler((swe, e) -> {
return Mono.fromRunnable(()->{
System.out.println( "accessDeniedHandler user trying to access unauthorized api end points : "+
swe.getPrincipal().block().getName()+
" in "+swe.getRequest().getPath());
swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
});
})
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.authenticationManager(authenticationManager)
.securityContextRepository(securityContext)
.authorizeExchange()
.pathMatchers(HttpMethod.OPTIONS).permitAll()
.pathMatchers("/auth/login").permitAll()
.anyExchange().authenticated()
.and()
.build();
}
As you can see, I want to simply deny all not authorized requests other than login or options based ones.
The login is working fine and I'm getting a token.
But trying to logout (a tweak that I implemented my self to make it state-full since I m only learning) is not working.
Here is my logout controller:
#RestController
#RequestMapping(AuthController.AUTH)
public class AuthController {
static final String AUTH = "/auth";
#Autowired
private AuthenticationService authService;
#PostMapping("/login")
public Mono<ResponseEntity<?>> login(#RequestBody AuthRequestParam arp) {
String username = arp.getUsername();
String password = arp.getPassword();
return authService.authenticate(username, password);
}
#PostMapping("/logout")
public Mono<ResponseEntity<?>> logout(#RequestBody LogoutRequestParam lrp) {
String token = lrp.getToken();
return authService.logout(token);
}
}
The logout request is as below:
As stated in images above, I believe that I m doing fine, however I m getting the error log message:
authenticationEntryPoint user trying to access unauthorized api end points : /127.0.0.1:45776 in /auth/logout
Here is my security context content:
/**
* we use this class to handle the bearer token extraction
* and pass it to the JWTReactiveAuthentication manager so in the end
* we produce
*
* simply said we extract the authorization we authenticate and
* depending on our implementation we produce a security context
*/
#Component
public class SecurityContextRepository implements ServerSecurityContextRepository {
#Autowired
private JWTReactiveAuthenticationManager authenticationManager;
#Override
public Mono<SecurityContext> load(ServerWebExchange swe) {
ServerHttpRequest request = swe.getRequest();
String authorizationHeaderContent = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if( authorizationHeaderContent !=null && !authorizationHeaderContent.isEmpty() && authorizationHeaderContent.startsWith("Bearer ")){
String token = authorizationHeaderContent.substring(7);
Authentication authentication = new UsernamePasswordAuthenticationToken(token, token);
return this.authenticationManager.authenticate(authentication).map((auth) -> {
return new SecurityContextImpl(auth);
});
}
return Mono.empty();
}
#Override
public Mono<Void> save(ServerWebExchange arg0, SecurityContext arg1) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
I'm unable to see or find any issue or error that I have made. Where is the mistake?
There's a difference in writing
//Wrong
Jwts.builder()
.setSubject(username)
.setClaims(claims)
and
//Correct
Jwts.builder()
.setClaims(claims)
.setSubject(username)
Indeed, look at setSubject method in the DefaultJwtBuilder class :
#Override
public JwtBuilder setSubject(String sub) {
if (Strings.hasText(sub)) {
ensureClaims().setSubject(sub);
} else {
if (this.claims != null) {
claims.setSubject(sub);
}
}
return this;
}
When setSubject(username) is called first, ensureClaims() creates a DefaultClaims without yours and if you call setClaims(claims) the precedent subject is lost ! This JWT builder is bogus.
Otherwise, you're importing the wrong Role class in JWTReactiveAuthenticationManager, you have to replace :
import org.springframework.context.support.BeanDefinitionDsl.Role;
by
import com.bridjitlearning.www.jwt.tutorial.domain.Role;
Last and not least, validateToken() will return always false because of the check(token). put call is coming too late, you have to be aware of that. Either you remove this check or you move the put execution before calling the check method.
I'am not sure about what you want to do with resignTokenMemory, so i'll let you fix it by your own:
public Boolean validateToken(String token) {
return !isTokenExpired(token) && resignTokenMemory.check(token);
}
Another thing, your token is valid only 28,8 second, for testing raison i recommend you to expiraiton * 1000.

spring 4.1 javaConfg setting to get requestCache working

similar to this:
Spring 3.1: Redirect after login not working
when an authenticated user becomes inauthenticated while deep-linking into a single page web app.
Spring security redirects to logon but:
SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
is null
thus i cannot devine the url or params to send re-authenticated user to requested page
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers() //redacted .
.antMatchers("/**").permitAll()
.and()
.formLogin()
.loginPage("/x/y/logon")
.usernameParameter("userLogon") //redacted
.loginProcessingUrl("/x/y/logon") //redacted
.defaultSuccessUrl("/x/", true)
.failureUrl("/x/y/logon?error=true")
.and()
.logout()
.logoutUrl("/x/y/logout")
.logoutSuccessUrl("/x/")
.permitAll();
}
}
-- controller --
#RequestMapping(method=RequestMethod.GET, value="/y/logon")
public ModelAndView logonHandler(HttpServletRequest request, HttpServletResponse response) {
List<Client> clients = //manager call for list of clients to show at logon
SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
if (savedRequest != null) {
String reqUrl = savedRequest.getRedirectUrl();
String[] urlParams = reqUrl.split("&");
String prefix = "";
String urlParam = "";
String cid = "";
try {
urlParam = urlParams[1];
} catch(IndexOutOfBoundsException ioob) { }
if (reqUrl.contains("cid=")) { cid = reqUrl.substring(reqUrl.indexOf("cid=")+4, reqUrl.indexOf("&")); }
if (reqUrl.contains("?")) { reqUrl = reqUrl.substring(0, reqUrl.indexOf("?")); }
prefix = reqUrl.substring(reqUrl.indexOf("/x/")+6, reqUrl.indexOf("/x/")+8);
reqUrl = reqUrl.substring(reqUrl.indexOf(prefix)+2);
if (reqUrl.contains("/")) {
reqUrl = reqUrl.substring(0, reqUrl.indexOf("/"));
}
request.setAttribute("requestUrl", prefix+reqUrl);
request.setAttribute("urlParam", urlParam);
request.setAttribute("cid", cid);
}
request.setAttribute("IPAddress", request.getRemoteAddr());
return new ModelAndView("x/logon", "clients", clients);
}
problem is, SavedRequest is null
is this an issue with:
alwaysUseDefaultTargetUrl property?
if yes, how in javaConfig does one set this property?
----- on edit to address comments ------
i'll explain my understanding of ea. .formLogon() settings:
logonPage() will be read by spring and control redirect to logon page when you are not authorized (cookie expire/db record del, etc). There are many ways that a session can not be authorized and spring needs to know what page to send unauth requests to. My manual logon handler only handles requests to the logon url.
usernameParameter() is to change from the default form input name thus obfuscating that one is using spring security.
loginProcessingUrl() this seems to conflict with the custom logonHandler, but i think its req to handle the post and allow for spring to create a secure sesson.
defaultSucessUrl() tells spring where to go after successful logon (the post request).
failureUrl() defines the url for failed logon.
nowhere in my custom logon handler for the get request, are those settings in conflict... i think... but i've read the docs and the Spring Security 3 book and lots of online resources and i still do not feel as though i have a solid understanding of spring security... so i may be way off

Resources