Search code examples
azuredockercorsjasperserver

JasperReports Server Bitnami Docker Image Running in Azure App Service Custom Web.xml


I am using the Bitnami JasperReports image v8.2.0 from https://hub.docker.com/r/bitnami/jasperreports in a docker container running in an Azure app service.

My Docker configuration file is:

version: '3.8'

services:
  jasperreports:
    image: docker.io/bitnami/jasperreports:8.2.0
    ports:
      - "8080:8080"
    volumes:
      - 'jasperreports_data:/bitnami/jasperreports'
      - "${WEBAPP_STORAGE_HOME}/site/wwwroot/config:/bitnami/jasperreports-mounted-conf"
    environment:
      - JASPERREPORTS_USERNAME=***
      - JASPERREPORTS_PASSWORD=***
      - JASPERREPORTS_DATABASE_TYPE=postgresql
      - JASPERREPORTS_DATABASE_HOST=bon-prod.postgres.database.azure.com
      - JASPERREPORTS_DATABASE_PORT_NUMBER=5432
      - JASPERREPORTS_DATABASE_USER=***
      - JASPERREPORTS_DATABASE_PASSWORD=***
      - JASPERREPORTS_DATABASE_NAME=jasper
      - JASPERREPORTS_SMTP_HOST=smtp.sendgrid.net
      - JASPERREPORTS_SMTP_PORT_NUMBER=587
      - JASPERREPORTS_SMTP_PROTOCOL=smtps
      - JASPERREPORTS_SMTP_USER=***
      - JASPERREPORTS_SMTP_PASSWORD=***
      # Additional environment variables for verbose logging
      - BITNAMI_DEBUG=true
      - JASPERREPORTS_LOGGING_LEVEL=DEBUG
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "5"

volumes:
  jasperreports_data:

I have added WEBSITES_ENABLE_APP_SERVICE_STORAGE=true as an app setting to enable storage in the Azure App Service.

I am getting a CORS error when calling the rest endpoint from my front-end domain. I struggled with a similar issue for weeks about 3 years ago and had a similar Stack Overflow question. Back then I was installing on a bare Linux server and resolved the issue using the web.xml below which has the CORS filter added (where sub.domain.com is my real sub-domain, of course):

<filter>
        <filter-name>CorsFilter</filter-name>
        <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
        <!--  Update allowed origins and remove localhost for non-dev environments -->
        <init-param>
            <param-name>cors.allowed.origins</param-name>
            <param-value>https://sub.domain.com</param-value>
        </init-param>
        <init-param>
            <param-name>cors.allowed.methods</param-name>
            <param-value>GET,POST,HEAD,PUT,OPTIONS,DELETE,PATCH</param-value>
        </init-param>
        <init-param>
            <param-name>cors.allowed.headers</param-name>
            <param-value>Cache-Control,X-Suppress-Basic,Origin,Accept,X-Requested-With,Content-Type,Pragma,accept-timezone,withCredentials,X-Remote-Domain,X-Is-Visualize,x-jrs-base-url,Content-Disposition,Content-Description,Content-Type,X-Requested-With,Accept,Accept-Encoding,Accept-Language,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Connection,Host,Authorization,Options</param-value>
        </init-param>
        <init-param>
            <param-name>cors.exposed.headers</param-name>
            <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials,Authorization</param-value>
        </init-param>
        <init-param>
            <param-name>cors.support.credentials</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>cors.preflight.maxage</param-name>
            <param-value>300</param-value>
        </init-param>
    </filter>

So I have SFTP'd the web.xml file to the /site/wwwroot/config folder on the Azure App Service to replace the Bitnami Container's built in web.xml as per the documentation on Bitnami's Docker Hub.

However, this has resulted in error:

https://bon-rpt.greydom.com/jasperserver/JavaScriptServlet 403 (Forbidden)
XMLHttpRequest.send @ JavaScriptServlet:52
ajax @ JavaScriptServlet:425
(anonymous) @ JavaScriptServlet:442
(anonymous) @ JavaScriptServlet:490Understand this errorAI
JavaScriptServlet:158 Failed to retrieve CSRF token
csrfTokenRetrieveFailed @ JavaScriptServlet:158
(anonymous) @ JavaScriptServlet:486
xhr.onreadystatechange @ JavaScriptServlet:421
XMLHttpRequest.send
XMLHttpRequest.send @ JavaScriptServlet:52
ajax @ JavaScriptServlet:425
(anonymous) @ JavaScriptServlet:442
(anonymous) @ JavaScriptServlet:490Understand this errorAI
content_script_bundle.js:1 Attempting initialization Mon Dec 02 2024 21:49:04 GMT+0100 (Central European Standard Time)
login.html:1 <meta name="apple-mobile-web-app-capable" content="yes"> is deprecated. Please include <meta name="mobile-web-app-capable" content="yes">Understand this warningAI
JavaScriptServlet:158 Failed to retrieve CSRF token

I am assuming that this is because my existing web.xml does not work within the Docker container.

How can I rather get the container's web.xml, and simply add the CORS filter, remembering that my Docker Container is in an Azure App Service?


Solution

  • Unfortunately, modifying the existing web.xml did not work. It caused other issues, like CSRF errors and other strange things.

    Thus, I solved it by using Nginx as a reverse proxy:

    version: '3.8'
    
    services:
      jasperreports:
        image: docker.io/bitnami/jasperreports:8.2.0
        volumes:
          - 'jasperreports_data:/bitnami/jasperreports'
          - "${WEBAPP_STORAGE_HOME}/site/wwwroot/config:/bitnami/jasperreports-mounted-conf"
        environment:
          - JASPERREPORTS_USERNAME=***
          - JASPERREPORTS_PASSWORD=***
          - JASPERREPORTS_DATABASE_TYPE=postgresql
          - JASPERREPORTS_DATABASE_HOST=bon-prod.postgres.database.azure.com
          - JASPERREPORTS_DATABASE_PORT_NUMBER=5432
          - JASPERREPORTS_DATABASE_USER=***
          - JASPERREPORTS_DATABASE_PASSWORD=***
          - JASPERREPORTS_DATABASE_NAME=jasper
          - JASPERREPORTS_SMTP_HOST=smtp.sendgrid.net
          - JASPERREPORTS_SMTP_PORT_NUMBER=587
          - JASPERREPORTS_SMTP_PROTOCOL=smtps
          - JASPERREPORTS_SMTP_USER=***
          - JASPERREPORTS_SMTP_PASSWORD=***
        
     nginx-proxy:
        image: nginx:alpine
        ports:
          - "80:8080"
        volumes:
          - "${WEBAPP_STORAGE_HOME}/site/wwwroot/nginx-conf/nginx.conf:/etc/nginx/conf.d/default.conf"
        depends_on:
          - jasperreports
    

    And nginx.conf:

    server {
        listen 8080;
        location / {
            proxy_pass http://jasperreports:8080; # Forward to JasperReports container
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            # Add CORS headers
            add_header 'Access-Control-Allow-Origin' 'https://***.greydom.com' always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
            add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always;
            add_header 'Access-Control-Allow-Credentials' 'true' always;
            # Handle preflight OPTIONS requests
            if ($request_method = OPTIONS) {
                add_header 'Access-Control-Allow-Origin' 'https://***.greydom.com';
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
                add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization';
                add_header 'Access-Control-Allow-Credentials' 'true';
                add_header 'Content-Length' 0;
                add_header 'Content-Type' 'text/plain';
                return 204;
            }
        }
    }