mkopylec / recaptcha-spring-boot-starter

Spring Boot starter for Google's reCAPTCHA
Apache License 2.0
109 stars 23 forks source link

spring security show reCaptcha by default #18

Open guntutur opened 5 years ago

guntutur commented 5 years ago

Hi, thanks for your contribution!

this might be not an issue rather a question.

i am aware of this #8

you said that

By default the captcha widget is shown after 5 unsuccessful login tries for the same username. If you want to change the treshold you can do it by setting: recaptcha.security.loginFailuresThreshold in application.yml file.

but what i want to achieve is something like recaptcha validation upon every login request without the need to previously check of unsuccessful login tries with the same username.

is it possible?

mkopylec commented 5 years ago

Just set recaptcha.security.loginFailuresThreshold to 0.

guntutur commented 5 years ago

Hi thanks for the quick response!

i tried your suggestion, but after login it gives me error like this

// 20190926162241 // http://localhost:8090/error

{ "timestamp": "2019-09-26T09:22:40.703+0000", "status": 999, "error": "None", "message": "No message available" }

this is the debug log :

2019-09-26 16:22:40,568 DEBUG [http-nio-127.0.0.1-8090-exec-6] o.h.l.Loader: Result set row: 0 2019-09-26 16:22:40,568 DEBUG [http-nio-127.0.0.1-8090-exec-6] o.h.l.Loader: Result row: 2019-09-26 16:22:40,574 DEBUG [http-nio-127.0.0.1-8090-exec-6] c.z.h.p.ProxyConnection: UimToolsConnectionPool - Executed rollback on connection oracle.jdbc.driver.T4CConnection@224a72fc due to dirty commit state on close(). 2019-09-26 16:22:40,673 DEBUG [http-nio-127.0.0.1-8090-exec-6] o.s.s.w.a.s.CompositeSessionAuthenticationStrategy: Delegating to org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy@6f1fe538 2019-09-26 16:22:40,675 DEBUG [http-nio-127.0.0.1-8090-exec-6] c.g.m.r.s.RecaptchaAuthenticationFilter: Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@5687b460: Principal: com.ssi.nossf.uim.tools.v1.config.security.CustomUserDetails@55458d8f; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 6F2683EB40E7CC11FA75DF9C43838844; Granted Authorities: Admin 2019-09-26 16:22:40,677 DEBUG [http-nio-127.0.0.1-8090-exec-6] c.g.m.r.s.l.InMemoryLoginFailuresManager: Clearing login failures for username: admin 2019-09-26 16:22:40,677 DEBUG [http-nio-127.0.0.1-8090-exec-6] c.g.m.r.s.l.LoginFailuresClearingHandler: Redirecting to DefaultSavedRequest Url: http://localhost:8090/error 2019-09-26 16:22:40,678 DEBUG [http-nio-127.0.0.1-8090-exec-6] o.s.s.w.DefaultRedirectStrategy: Redirecting to 'http://localhost:8090/error' 2019-09-26 16:22:40,679 DEBUG [http-nio-127.0.0.1-8090-exec-6] o.s.s.w.h.w.HstsHeaderWriter: Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@65086c00 2019-09-26 16:22:40,679 DEBUG [http-nio-127.0.0.1-8090-exec-6] o.s.s.w.c.HttpSessionSecurityContextRepository: SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@5687b460: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@5687b460: Principal: com.ssi.nossf.uim.tools.v1.config.security.CustomUserDetails@55458d8f; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 6F2683EB40E7CC11FA75DF9C43838844; Granted Authorities: Admin' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@63bcc147 2019-09-26 16:22:40,679 DEBUG [http-nio-127.0.0.1-8090-exec-6] o.s.s.w.c.SecurityContextPersistenceFilter: SecurityContextHolder now cleared, as request processing completed 2019-09-26 16:22:40,686 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.u.m.AntPathRequestMatcher: Checking match of request : '/error'; against '/resources/*' 2019-09-26 16:22:40,686 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 2019-09-26 16:22:40,686 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 2019-09-26 16:22:40,686 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.c.HttpSessionSecurityContextRepository: Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@5687b460: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@5687b460: Principal: com.ssi.nossf.uim.tools.v1.config.security.CustomUserDetails@55458d8f; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 6F2683EB40E7CC11FA75DF9C43838844; Granted Authorities: Admin' 2019-09-26 16:22:40,686 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter' 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 4 of 12 in additional filter chain; firing Filter: 'CorsFilter' 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter' 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.u.m.AntPathRequestMatcher: Checking match of request : '/error'; against '/logout' 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 6 of 12 in additional filter chain; firing Filter: 'RecaptchaAuthenticationFilter' 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.u.m.AntPathRequestMatcher: Request 'GET /error' doesn't match 'POST /login' 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.DefaultSavedRequest: pathInfo: both null (property equals) 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.DefaultSavedRequest: queryString: both null (property equals) 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.DefaultSavedRequest: requestURI: arg1=/error; arg2=/error (property equals) 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.DefaultSavedRequest: serverPort: arg1=8090; arg2=8090 (property equals) 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.DefaultSavedRequest: requestURL: arg1=http://localhost:8090/error; arg2=http://localhost:8090/error (property equals) 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.DefaultSavedRequest: scheme: arg1=http; arg2=http (property equals) 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.DefaultSavedRequest: serverName: arg1=localhost; arg2=localhost (property equals) 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.DefaultSavedRequest: contextPath: arg1=; arg2= (property equals) 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.DefaultSavedRequest: servletPath: arg1=/error; arg2=/error (property equals) 2019-09-26 16:22:40,687 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.s.HttpSessionRequestCache: Removing DefaultSavedRequest from session if present 2019-09-26 16:22:40,688 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 2019-09-26 16:22:40,688 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' 2019-09-26 16:22:40,688 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.a.AnonymousAuthenticationFilter: SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@5687b460: Principal: com.ssi.nossf.uim.tools.v1.config.security.CustomUserDetails@55458d8f; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 6F2683EB40E7CC11FA75DF9C43838844; Granted Authorities: Admin' 2019-09-26 16:22:40,688 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter' 2019-09-26 16:22:40,688 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 2019-09-26 16:22:40,688 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 2019-09-26 16:22:40,688 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.u.m.AntPathRequestMatcher: Checking match of request : '/error'; against '/logout' 2019-09-26 16:22:40,689 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.a.i.FilterSecurityInterceptor: Secure object: FilterInvocation: URL: /error; Attributes: [fullyAuthenticated] 2019-09-26 16:22:40,689 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.a.i.FilterSecurityInterceptor: Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@5687b460: Principal: com.ssi.nossf.uim.tools.v1.config.security.CustomUserDetails@55458d8f; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 6F2683EB40E7CC11FA75DF9C43838844; Granted Authorities: Admin 2019-09-26 16:22:40,689 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.a.v.AffirmativeBased: Voter: org.springframework.security.web.access.expression.WebExpressionVoter@573bc4b3, returned: 1 2019-09-26 16:22:40,689 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.a.i.FilterSecurityInterceptor: Authorization successful 2019-09-26 16:22:40,689 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.a.i.FilterSecurityInterceptor: RunAsManager did not change Authentication object 2019-09-26 16:22:40,689 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.FilterChainProxy: /error reached end of additional filter chain; proceeding with original chain 2019-09-26 16:22:40,689 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.w.s.DispatcherServlet: GET "/error", parameters={} 2019-09-26 16:22:40,691 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.w.s.m.m.a.RequestMappingHandlerMapping: Mapped to public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2019-09-26 16:22:40,718 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.w.s.m.m.a.HttpEntityMethodProcessor: Using 'application/json', given [/] and supported [application/json, application/+json, application/json, application/*+json] 2019-09-26 16:22:40,718 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.w.s.m.m.a.HttpEntityMethodProcessor: Writing [{timestamp=Thu Sep 26 16:22:40 WIB 2019, status=999, error=None, message=No message available}] 2019-09-26 16:22:40,738 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.h.w.HstsHeaderWriter: Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@65086c00 2019-09-26 16:22:40,739 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.w.s.DispatcherServlet: Completed 500 INTERNAL_SERVER_ERROR 2019-09-26 16:22:40,739 DEBUG [http-nio-127.0.0.1-8090-exec-7] o.s.s.w.a.ExceptionTranslationFilter: Chain processed normally

guntutur commented 5 years ago

btw i'm trying to implement this to spring mvc with default web security login

guntutur commented 5 years ago

i see your log here stated that

2019-09-26 16:22:40,677 DEBUG [http-nio-127.0.0.1-8090-exec-6] c.g.m.r.s.l.LoginFailuresClearingHandler: Redirecting to DefaultSavedRequest Url: http://localhost:8090/error

i dont understand why upon successful login with captcha and my database authentication, LoginFailuresClearingHandler redirect me to /error

i can assure that my database authentication is successful from this line :

019-09-26 16:22:40,675 DEBUG [http-nio-127.0.0.1-8090-exec-6] c.g.m.r.s.RecaptchaAuthenticationFilter: Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@5687b460: Principal: com.ssi.nossf.uim.tools.v1.config.security.CustomUserDetails@55458d8f; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 6F2683EB40E7CC11FA75DF9C43838844; Granted Authorities: Admin

mkopylec commented 5 years ago

Can you check this using: https://github.com/mkopylec/recaptcha-spring-boot-starter-samples ?

guntutur commented 5 years ago

Hi @mkopylec i was able to integrate it using the starter, following your instruction here successfully :

Just set recaptcha.security.loginFailuresThreshold to 0.

but having some strange behaviour with this steps :

  1. valid credential (username and password) provided and submitted without recapctha being ticked
  2. it returns to the login without giving any error
  3. valid credential (username and password) provided and submitted with recapctha being ticked
  4. it returns to the login with addition of these query parameter on the url :

/login?recaptchaError&showRecaptcha

  1. and for the third attempt, given valid credential and recapctha being ticked, then i am able to successfully logged in to the application

do you know why this behaviour happens? i could provide log and code sample, just name what you need.

Thanks!

mkopylec commented 5 years ago

I need to investigate it on my own. If I'll need some code from you I'll let you know.

guntutur commented 5 years ago

Great! btw the steps i mentioned applies one after the other without refresh the browser or restarting the application

mkopylec commented 5 years ago

You have to do two things to get it work. Set login failures treshold to 0 in application.yml:

recaptcha:
  security:
    login-failures-threshold: 0

Remove the condition for displaying reCaptcha widget from your login form page. Wrong:

<div th:if="${#httpServletRequest.getParameter('showRecaptcha')}" class="g-recaptcha" data-sitekey="yoursitekey"></div>

Right:

<div class="g-recaptcha" data-sitekey="yoursitekey"></div>
guntutur commented 5 years ago

Hi @mkopylec

You have to do two things to get it work. Set login failures treshold to 0 in application.yml:

recaptcha:
  security:
    login-failures-threshold: 0

Remove the condition for displaying reCaptcha widget from your login form page. Wrong:

<div th:if="${#httpServletRequest.getParameter('showRecaptcha')}" class="g-recaptcha" data-sitekey="yoursitekey"></div>

Right:

<div class="g-recaptcha" data-sitekey="yoursitekey"></div>

unfortunately, this is exactly the configuration and set up that i had in my code before facing the strange behaviour that i posted earlier. do you mind sharing your tested code which connect to database? i would be happy to try it

mkopylec commented 5 years ago

I've tested it using https://github.com/mkopylec/recaptcha-spring-boot-starter-samples The sample uses in-memory users and also counts login failures in-memory. It works that way. If you are using database instead in-memory storage it should act the same. If it's not then there is some kind of problem in your code which is communictaing with database. Or maybe your spring security configuration is wrong.

If you want me to help you with that you have to share me some code that suposed to work.