Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSO failing with "Missing attribute 'email' in attributes" when using Authelia #1254

Closed
pcanham opened this issue May 20, 2024 · 4 comments · Fixed by #1265
Closed

SSO failing with "Missing attribute 'email' in attributes" when using Authelia #1254

pcanham opened this issue May 20, 2024 · 4 comments · Fixed by #1265

Comments

@pcanham
Copy link
Contributor

pcanham commented May 20, 2024

Testing the SSO functionality against authelia using OAUTH2, I am getting the error that Stirling PDF cant find the email attribute but it is being passed over.

Stirling-PDF Version: v0.24.4

Here is my docker-compose for Stirling PDF

  stirling-pdf:
    image: frooodle/s-pdf:0.24.4
    container_name: stirling-pdf
    logging:
      options:
        max-size: "100m"
        max-file: "5"    
    environment:
      - PUID=1000
      - PGID=1000
      - TZ="Etc/UTC"
      - LANGS="en_GB"
      - SYSTEM_DEFAULTLOCALE="en_GB"
      - INSTALL_BOOK_AND_ADVANCED_HTML_OPS=true
      - DOCKER_ENABLE_SECURITY=true
      - SECURITY_ENABLELOGIN=true
      - SECURITY_OAUTH2_ENABLED=true
      - SECURITY_OAUTH2_AUTOCREATEUSER=true
      - SECURITY_OAUTH2_ISSUER=https://auth.<redacted>
      - SECURITY_OAUTH2_CLIENTID=stirling-pdf
      - SECURITY_OAUTH2_CLIENTSECRET=<redacted>
      - UI_APPNAME=Stirling-PDF
      - UI_HOMEDESCRIPTION=Stirling-PDF self hosted
      - UI_APPNAMENAVBAR=Stirling-PDF
    volumes:
      - /data/stirling-pdf/config:/configs
      - /data/stirling-pdf/data:/data
       healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
      interval: 5s
      timeout: 10s
      retries: 16
      start_period: 120s   
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.stirling-pdf.entrypoints=web"
      - "traefik.http.routers.stirling-pdf.rule=Host(`stirling-pdf.<redacted>`)"
      - "traefik.http.services.stirling-pdf.loadbalancer.server.scheme=http"
      - "traefik.http.services.stirling-pdf.loadbalancer.server.port=8080"
      - "traefik.http.services.stirling-pdf.loadbalancer.passhostheader=true"
      - "traefik.http.middlewares.stirling-pdf-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.stirling-pdf.middlewares=stirling-pdf-https-redirect"
      - "traefik.http.routers.stirling-pdf-secure.entrypoints=websecure"
      - "traefik.http.routers.stirling-pdf-secure.rule=Host(`stirling-pdf.<redacted>`)"
      - "traefik.http.routers.stirling-pdf-secure.service=stirling-pdf"
      - "traefik.http.routers.stirling-pdf-secure.tls=true"
      - "traefik.http.routers.stirling-pdf-secure.tls.domains[0].main=stirling-pdf.<redacted>"
      - "traefik.http.routers.stirling-pdf-secure.tls.certresolver=letsencrypt"      
    restart: unless-stopped
    networks:
      - traefik_proxy

networks:
  traefik_proxy:
    external:
      name: traefik_proxy

Error

20:49:04.248 [http-nio-8080-exec-1] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
java.lang.IllegalArgumentException: Missing attribute 'email' in attributes
	at org.springframework.security.oauth2.core.user.DefaultOAuth2User.<init>(DefaultOAuth2User.java:72)
	at org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService.loadUser(DefaultOAuth2UserService.java:118)
	at org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider.authenticate(OAuth2LoginAuthenticationProvider.java:119)
	at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
	at org.springframework.security.authentication.ObservationAuthenticationManager.lambda$authenticate$1(ObservationAuthenticationManager.java:54)
	at io.micrometer.observation.Observation.observe(Observation.java:565)
	at org.springframework.security.authentication.ObservationAuthenticationManager.authenticate(ObservationAuthenticationManager.java:53)
	at org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication(OAuth2LoginAuthenticationFilter.java:196)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:231)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:221)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
	at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
	at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:181)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
	at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
	at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
	at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
	at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
	at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
	at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
	at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
	at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
	at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
	at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
	at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
	at org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323)
	at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224)
	at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	at org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
	at org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:230)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
	at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:109)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:735)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
	at java.base/java.lang.Thread.run(Thread.java:1583)
@K-J-VV
Copy link

K-J-VV commented May 21, 2024

I'm receiving similar problem, but with Keycloak. following this documentation to setup OAuth2

Stirling starts up fine, but when I click the SSO button the webpage I'm taken to displays:

{
    "error": "invalid_request",
    "error_description": "The scope of your request is missing. Please ensure some scopes are requested. If you have any questions, you may contact the administrator of the application."
}

However my Auth provider is passing along scopes.

@K-J-VV
Copy link

K-J-VV commented May 21, 2024

@pcanham

Possible fix!

Enter the container and edit the /config/settings.yml file. The only lines I modified/uncommented were oauth2 and scopes.

security:
  enableLogin: false # set to 'true' to enable login
  csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
  loginAttemptCount: 5 # lock user account after 5 tries
  loginResetTimeMinutes : 120 # lock account for 2 hours after x attempts
#  initialLogin:
#    username: "admin" # Initial username for the first login
#    password: "stirling" # Initial password for the first login
  oauth2:
#    enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work)
#    issuer: "" # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point
#    clientId: "" # Client ID from your provider
#    clientSecret: "" # Client Secret from your provider
#    autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
#    useAsUsername: "email" # Default is 'email'; custom fields can be used as the username
    scopes: "openid, profile, email" # Specify the scopes for which the application will request permissions
#    provider: "google" # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak'

After that, stop & remove the container, re-spin, and then SSO worked for me

Assuming this works for you, there may need to be creation for a new environment variable (e.g., SECURITY_OAUTH2_SCOPES). Looking through issues looks like someone else trying to use Google may need to customize their scopes as well #1258 (comment)

@pcanham
Copy link
Contributor Author

pcanham commented May 21, 2024

Just tested and the workaround works, also noticed when I login I can see what scopes Stirling PDF has requested from Authelia

Working

Working

Failing

Failing

@pcanham
Copy link
Contributor Author

pcanham commented May 21, 2024

@K-J-VV I have been going through the code and look's like the environment variable already exists. Added the following to my docker-compose and things are working well (I deleted the configs to make sure no old configs didn't come back to haunt me)

SECURITY_OAUTH2_SCOPES=openid,profile,email

Working example for me;

---
version: "3.8"
services:
  stirling-pdf:
    image: frooodle/s-pdf:0.24.4
    container_name: stirling-pdf
    logging:
      options:
        max-size: "100m"
        max-file: "5"    
    environment:
      - PUID=1000
      - PGID=1000
      - TZ="Etc/UTC"
      - LANGS="en_GB"
      - SYSTEM_DEFAULTLOCALE="en_GB"
      - INSTALL_BOOK_AND_ADVANCED_HTML_OPS=true
      - DOCKER_ENABLE_SECURITY=true
      - SECURITY_ENABLELOGIN=true
      - SECURITY_OAUTH2_ENABLED=true
      - SECURITY_OAUTH2_AUTOCREATEUSER=true
      - SECURITY_OAUTH2_ISSUER=https://<redacted>
      - SECURITY_OAUTH2_CLIENTID=stirling-pdf
      - SECURITY_OAUTH2_CLIENTSECRET=<redacted>
      - SECURITY_OAUTH2_SCOPES=openid,profile,email
      - UI_APPNAME=Stirling-PDF
      - UI_HOMEDESCRIPTION=Stirling-PDF self hosted
      - UI_APPNAMENAVBAR=Stirling-PDF
    volumes:
      - /data/stirling-pdf/config:/configs
      - /data/stirling-pdf/data:/data
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
      interval: 5s
      timeout: 10s
      retries: 16
      start_period: 120s     
    restart: unless-stopped

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants