Handle error on Spring Boot at custom authentication filter












0















I'm working in a spring-boot application on my backend and I want to use firebase to make the authentication process.
I setup properly the firebase in my spring-boot project and added the security layer following this open source repository: https://github.com/savicprvoslav/Spring-Boot-starter



Because the Firebase token has a lifetime of 1 hour I need to handle an error when the Firebase SDK throws a FirebaseAuthException. The issue is I'm not being able to handle exception inside of my FirebaseFilter. The backend always returns the default error page with timestamp, error, message and status 500. I want to change it to return only the HTTP status code 401.



I also would like to change the default error page when the URL path doesn't exist to return only 404 as a good REST API should returns.



I tried to use @ExceptionHandler and @ControllerAdvice (following this article https://www.baeldung.com/exception-handling-for-rest-with-spring) but it didn't work. I'm very new Spring Framework developer so I guess I'm missing something...



My .gradle file:



implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation('org.springframework.boot:spring-boot-starter-web')
implementation('org.springframework.boot:spring-boot-starter-security')
implementation('org.flywaydb:flyway-core:5.2.1')
implementation('com.fasterxml.jackson.module:jackson-module-kotlin')
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation('com.google.firebase:firebase-admin:6.5.0')
implementation('io.springfox:springfox-swagger2:2.9.2')
implementation('io.springfox:springfox-swagger-ui:2.9.2')
runtimeOnly('org.postgresql:postgresql')
testImplementation('org.springframework.boot:spring-boot-starter-test')


My WebSecurityConfigurerAdapter:



@Configuration
inner class ApplicationSecurity : WebSecurityConfigurerAdapter(false) {
@Autowired(required = false)
lateinit var firebaseService: FirebaseServiceContract

override fun configure(web: WebSecurity) {
web.ignoring().antMatchers(
"/api/users",
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources",
"/configuration/security", "/swagger-ui.html",
"/webjars/**", "/swagger-resources/configuration/ui",
"/swagge‌r-ui.html", "/docs/**",
"/swagger-resources/configuration/security"
)
}

override fun configure(http: HttpSecurity) {
http.addFilterBefore(tokenAuthorizationFilter(), BasicAuthenticationFilter::class.java)
.authorizeRequests()
.antMatchers("/api/**").hasAnyRole(Roles.USER)
.and().csrf().disable().anonymous().authorities(Roles.ROLE_ANONYMOUS)
}

private fun tokenAuthorizationFilter(): FirebaseFilter? {
return FirebaseFilter(firebaseService)
}
}


My FirebaseFilter:



class FirebaseFilter(private val firebaseService: FirebaseServiceContract) : OncePerRequestFilter() {
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
val xAuth = request.getHeader(HEADER_NAME)?.removePrefix("Bearer ")
if (xAuth.isNullOrBlank()) {
chain.doFilter(request, response)
return
} else {
try {
// Fire FirebaseAuth.getInstance().verifyIdToken
val holder = firebaseService.parseToken(xAuth)

val userName = holder.getUid()

val auth = FirebaseAuthenticationToken(userName, holder)
SecurityContextHolder.getContext().authentication = auth

chain.doFilter(request, response)
} catch (e: FirebaseTokenInvalidException) {
throw SecurityException(e)
}
}
}


My Firebase parser:



class FirebaseParser {

fun parseToken(idToken: String): FirebaseTokenHolder {
if (idToken.isBlank()) {
throw IllegalArgumentException("Blank Token")
}

try {
val authTask = FirebaseAuth.getInstance().verifyIdToken(idToken)
FirebaseAuth.getInstance().getUser(authTask.uid)

return FirebaseTokenHolder(authTask)
} catch (e: FirebaseAuthException) {
throw FirebaseTokenInvalidException(e.message)
}
}
}









share|improve this question





























    0















    I'm working in a spring-boot application on my backend and I want to use firebase to make the authentication process.
    I setup properly the firebase in my spring-boot project and added the security layer following this open source repository: https://github.com/savicprvoslav/Spring-Boot-starter



    Because the Firebase token has a lifetime of 1 hour I need to handle an error when the Firebase SDK throws a FirebaseAuthException. The issue is I'm not being able to handle exception inside of my FirebaseFilter. The backend always returns the default error page with timestamp, error, message and status 500. I want to change it to return only the HTTP status code 401.



    I also would like to change the default error page when the URL path doesn't exist to return only 404 as a good REST API should returns.



    I tried to use @ExceptionHandler and @ControllerAdvice (following this article https://www.baeldung.com/exception-handling-for-rest-with-spring) but it didn't work. I'm very new Spring Framework developer so I guess I'm missing something...



    My .gradle file:



    implementation('org.springframework.boot:spring-boot-starter-data-jpa')
    implementation('org.springframework.boot:spring-boot-starter-web')
    implementation('org.springframework.boot:spring-boot-starter-security')
    implementation('org.flywaydb:flyway-core:5.2.1')
    implementation('com.fasterxml.jackson.module:jackson-module-kotlin')
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation('com.google.firebase:firebase-admin:6.5.0')
    implementation('io.springfox:springfox-swagger2:2.9.2')
    implementation('io.springfox:springfox-swagger-ui:2.9.2')
    runtimeOnly('org.postgresql:postgresql')
    testImplementation('org.springframework.boot:spring-boot-starter-test')


    My WebSecurityConfigurerAdapter:



    @Configuration
    inner class ApplicationSecurity : WebSecurityConfigurerAdapter(false) {
    @Autowired(required = false)
    lateinit var firebaseService: FirebaseServiceContract

    override fun configure(web: WebSecurity) {
    web.ignoring().antMatchers(
    "/api/users",
    "/v2/api-docs",
    "/configuration/ui",
    "/swagger-resources",
    "/configuration/security", "/swagger-ui.html",
    "/webjars/**", "/swagger-resources/configuration/ui",
    "/swagge‌r-ui.html", "/docs/**",
    "/swagger-resources/configuration/security"
    )
    }

    override fun configure(http: HttpSecurity) {
    http.addFilterBefore(tokenAuthorizationFilter(), BasicAuthenticationFilter::class.java)
    .authorizeRequests()
    .antMatchers("/api/**").hasAnyRole(Roles.USER)
    .and().csrf().disable().anonymous().authorities(Roles.ROLE_ANONYMOUS)
    }

    private fun tokenAuthorizationFilter(): FirebaseFilter? {
    return FirebaseFilter(firebaseService)
    }
    }


    My FirebaseFilter:



    class FirebaseFilter(private val firebaseService: FirebaseServiceContract) : OncePerRequestFilter() {
    override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
    val xAuth = request.getHeader(HEADER_NAME)?.removePrefix("Bearer ")
    if (xAuth.isNullOrBlank()) {
    chain.doFilter(request, response)
    return
    } else {
    try {
    // Fire FirebaseAuth.getInstance().verifyIdToken
    val holder = firebaseService.parseToken(xAuth)

    val userName = holder.getUid()

    val auth = FirebaseAuthenticationToken(userName, holder)
    SecurityContextHolder.getContext().authentication = auth

    chain.doFilter(request, response)
    } catch (e: FirebaseTokenInvalidException) {
    throw SecurityException(e)
    }
    }
    }


    My Firebase parser:



    class FirebaseParser {

    fun parseToken(idToken: String): FirebaseTokenHolder {
    if (idToken.isBlank()) {
    throw IllegalArgumentException("Blank Token")
    }

    try {
    val authTask = FirebaseAuth.getInstance().verifyIdToken(idToken)
    FirebaseAuth.getInstance().getUser(authTask.uid)

    return FirebaseTokenHolder(authTask)
    } catch (e: FirebaseAuthException) {
    throw FirebaseTokenInvalidException(e.message)
    }
    }
    }









    share|improve this question



























      0












      0








      0








      I'm working in a spring-boot application on my backend and I want to use firebase to make the authentication process.
      I setup properly the firebase in my spring-boot project and added the security layer following this open source repository: https://github.com/savicprvoslav/Spring-Boot-starter



      Because the Firebase token has a lifetime of 1 hour I need to handle an error when the Firebase SDK throws a FirebaseAuthException. The issue is I'm not being able to handle exception inside of my FirebaseFilter. The backend always returns the default error page with timestamp, error, message and status 500. I want to change it to return only the HTTP status code 401.



      I also would like to change the default error page when the URL path doesn't exist to return only 404 as a good REST API should returns.



      I tried to use @ExceptionHandler and @ControllerAdvice (following this article https://www.baeldung.com/exception-handling-for-rest-with-spring) but it didn't work. I'm very new Spring Framework developer so I guess I'm missing something...



      My .gradle file:



      implementation('org.springframework.boot:spring-boot-starter-data-jpa')
      implementation('org.springframework.boot:spring-boot-starter-web')
      implementation('org.springframework.boot:spring-boot-starter-security')
      implementation('org.flywaydb:flyway-core:5.2.1')
      implementation('com.fasterxml.jackson.module:jackson-module-kotlin')
      implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
      implementation("org.jetbrains.kotlin:kotlin-reflect")
      implementation('com.google.firebase:firebase-admin:6.5.0')
      implementation('io.springfox:springfox-swagger2:2.9.2')
      implementation('io.springfox:springfox-swagger-ui:2.9.2')
      runtimeOnly('org.postgresql:postgresql')
      testImplementation('org.springframework.boot:spring-boot-starter-test')


      My WebSecurityConfigurerAdapter:



      @Configuration
      inner class ApplicationSecurity : WebSecurityConfigurerAdapter(false) {
      @Autowired(required = false)
      lateinit var firebaseService: FirebaseServiceContract

      override fun configure(web: WebSecurity) {
      web.ignoring().antMatchers(
      "/api/users",
      "/v2/api-docs",
      "/configuration/ui",
      "/swagger-resources",
      "/configuration/security", "/swagger-ui.html",
      "/webjars/**", "/swagger-resources/configuration/ui",
      "/swagge‌r-ui.html", "/docs/**",
      "/swagger-resources/configuration/security"
      )
      }

      override fun configure(http: HttpSecurity) {
      http.addFilterBefore(tokenAuthorizationFilter(), BasicAuthenticationFilter::class.java)
      .authorizeRequests()
      .antMatchers("/api/**").hasAnyRole(Roles.USER)
      .and().csrf().disable().anonymous().authorities(Roles.ROLE_ANONYMOUS)
      }

      private fun tokenAuthorizationFilter(): FirebaseFilter? {
      return FirebaseFilter(firebaseService)
      }
      }


      My FirebaseFilter:



      class FirebaseFilter(private val firebaseService: FirebaseServiceContract) : OncePerRequestFilter() {
      override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
      val xAuth = request.getHeader(HEADER_NAME)?.removePrefix("Bearer ")
      if (xAuth.isNullOrBlank()) {
      chain.doFilter(request, response)
      return
      } else {
      try {
      // Fire FirebaseAuth.getInstance().verifyIdToken
      val holder = firebaseService.parseToken(xAuth)

      val userName = holder.getUid()

      val auth = FirebaseAuthenticationToken(userName, holder)
      SecurityContextHolder.getContext().authentication = auth

      chain.doFilter(request, response)
      } catch (e: FirebaseTokenInvalidException) {
      throw SecurityException(e)
      }
      }
      }


      My Firebase parser:



      class FirebaseParser {

      fun parseToken(idToken: String): FirebaseTokenHolder {
      if (idToken.isBlank()) {
      throw IllegalArgumentException("Blank Token")
      }

      try {
      val authTask = FirebaseAuth.getInstance().verifyIdToken(idToken)
      FirebaseAuth.getInstance().getUser(authTask.uid)

      return FirebaseTokenHolder(authTask)
      } catch (e: FirebaseAuthException) {
      throw FirebaseTokenInvalidException(e.message)
      }
      }
      }









      share|improve this question
















      I'm working in a spring-boot application on my backend and I want to use firebase to make the authentication process.
      I setup properly the firebase in my spring-boot project and added the security layer following this open source repository: https://github.com/savicprvoslav/Spring-Boot-starter



      Because the Firebase token has a lifetime of 1 hour I need to handle an error when the Firebase SDK throws a FirebaseAuthException. The issue is I'm not being able to handle exception inside of my FirebaseFilter. The backend always returns the default error page with timestamp, error, message and status 500. I want to change it to return only the HTTP status code 401.



      I also would like to change the default error page when the URL path doesn't exist to return only 404 as a good REST API should returns.



      I tried to use @ExceptionHandler and @ControllerAdvice (following this article https://www.baeldung.com/exception-handling-for-rest-with-spring) but it didn't work. I'm very new Spring Framework developer so I guess I'm missing something...



      My .gradle file:



      implementation('org.springframework.boot:spring-boot-starter-data-jpa')
      implementation('org.springframework.boot:spring-boot-starter-web')
      implementation('org.springframework.boot:spring-boot-starter-security')
      implementation('org.flywaydb:flyway-core:5.2.1')
      implementation('com.fasterxml.jackson.module:jackson-module-kotlin')
      implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
      implementation("org.jetbrains.kotlin:kotlin-reflect")
      implementation('com.google.firebase:firebase-admin:6.5.0')
      implementation('io.springfox:springfox-swagger2:2.9.2')
      implementation('io.springfox:springfox-swagger-ui:2.9.2')
      runtimeOnly('org.postgresql:postgresql')
      testImplementation('org.springframework.boot:spring-boot-starter-test')


      My WebSecurityConfigurerAdapter:



      @Configuration
      inner class ApplicationSecurity : WebSecurityConfigurerAdapter(false) {
      @Autowired(required = false)
      lateinit var firebaseService: FirebaseServiceContract

      override fun configure(web: WebSecurity) {
      web.ignoring().antMatchers(
      "/api/users",
      "/v2/api-docs",
      "/configuration/ui",
      "/swagger-resources",
      "/configuration/security", "/swagger-ui.html",
      "/webjars/**", "/swagger-resources/configuration/ui",
      "/swagge‌r-ui.html", "/docs/**",
      "/swagger-resources/configuration/security"
      )
      }

      override fun configure(http: HttpSecurity) {
      http.addFilterBefore(tokenAuthorizationFilter(), BasicAuthenticationFilter::class.java)
      .authorizeRequests()
      .antMatchers("/api/**").hasAnyRole(Roles.USER)
      .and().csrf().disable().anonymous().authorities(Roles.ROLE_ANONYMOUS)
      }

      private fun tokenAuthorizationFilter(): FirebaseFilter? {
      return FirebaseFilter(firebaseService)
      }
      }


      My FirebaseFilter:



      class FirebaseFilter(private val firebaseService: FirebaseServiceContract) : OncePerRequestFilter() {
      override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
      val xAuth = request.getHeader(HEADER_NAME)?.removePrefix("Bearer ")
      if (xAuth.isNullOrBlank()) {
      chain.doFilter(request, response)
      return
      } else {
      try {
      // Fire FirebaseAuth.getInstance().verifyIdToken
      val holder = firebaseService.parseToken(xAuth)

      val userName = holder.getUid()

      val auth = FirebaseAuthenticationToken(userName, holder)
      SecurityContextHolder.getContext().authentication = auth

      chain.doFilter(request, response)
      } catch (e: FirebaseTokenInvalidException) {
      throw SecurityException(e)
      }
      }
      }


      My Firebase parser:



      class FirebaseParser {

      fun parseToken(idToken: String): FirebaseTokenHolder {
      if (idToken.isBlank()) {
      throw IllegalArgumentException("Blank Token")
      }

      try {
      val authTask = FirebaseAuth.getInstance().verifyIdToken(idToken)
      FirebaseAuth.getInstance().getUser(authTask.uid)

      return FirebaseTokenHolder(authTask)
      } catch (e: FirebaseAuthException) {
      throw FirebaseTokenInvalidException(e.message)
      }
      }
      }






      java firebase spring-boot spring-security firebase-authentication






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 25 '18 at 21:08









      Frank van Puffelen

      241k29387414




      241k29387414










      asked Nov 25 '18 at 20:35









      EsdrasEsdras

      100118




      100118
























          0






          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53471695%2fhandle-error-on-spring-boot-at-custom-authentication-filter%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53471695%2fhandle-error-on-spring-boot-at-custom-authentication-filter%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Create new schema in PostgreSQL using DBeaver

          Deepest pit of an array with Javascript: test on Codility

          Costa Masnaga