Handle error on Spring Boot at custom authentication filter
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",
"/swagger-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
add a comment |
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",
"/swagger-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
add a comment |
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",
"/swagger-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
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",
"/swagger-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
java firebase spring-boot spring-security firebase-authentication
edited Nov 25 '18 at 21:08
Frank van Puffelen
241k29387414
241k29387414
asked Nov 25 '18 at 20:35
EsdrasEsdras
100118
100118
add a comment |
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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