MockServer: Mocking external http/https response refuses connection on 80/443

4.6k views Asked by At

What I was trying to achieve is mocking the response of google oauth2 endpoint. Here is my setup:

# docker-compose.yml
version: '3.8'

services:
  busybox:
    image: yauritux/busybox-curl:latest
    command: tail -f /dev/null
    networks:
      - our-network

  api-mock:
    image: mockserver/mockserver
    networks:
      our-network:
        aliases:
          - oauth2.googleapis.com
    environment:
      MOCKSERVER_INITIALIZATION_JSON_PATH: /api-mock/expectations_init.json
      MOCKSERVER_WATCH_INITIALIZATION_JSON: 'true'
    volumes:
      - ./api-mock/:/api-mock
    ports:
      - 1080:1080

networks:
  our-network:

Our Mockserver expectations

# ./api-mock/expectations_init.json
[
  {
    "httpRequest": {
      "method": "GET",
      "path": "/token",
      "secure": true
    },
    "httpResponse": {
      "statusCode": 200,
      "body": "Hello World - secure"
    }
  },
  {
    "httpRequest": {
      "method": "GET",
      "path": "/token",
      "secure": false
    },
    "httpResponse": {
      "statusCode": 200,
      "body": "Hello World"
    }
  }
]

my project structure

stackoverflow
    - ./api-mock
        - expectations_init.json
    - docker-compose.yml

To run this minimal example just run

docker-compose up -d

See the dashboard of the mockserver

localhost:1080/mockserver/dashboard

What I expected to work is:

docker exec stackoverflow_busybox_1 curl -k https://oauth2.googleapis.com/token
# curl: (7) Failed connect to oauth2.googleapis.com:443; Connection refused

What worked instead is:

docker exec stackoverflow_busybox_1 curl -k https://oauth2.googleapis.com:1080/token
# Hello World - secure

Same here, expected to work:

docker exec stackoverflow_busybox_1 curl -k http://oauth2.googleapis.com/token
# curl: (7) Failed connect to oauth2.googleapis.com:80; Connection refused

and what worked instead:

docker exec stackoverflow_busybox_1 curl -k http://oauth2.googleapis.com:1080/token
# Hello World

What did I miss to configure to get a response without passing the port, because I have no control about, what URL the vendor code is calling. I can't find any hint for this use case in the documentation of the mockserver to achieve this. Maybe this is an issue of docker/docker-compose?

Best regards

2

There are 2 answers

2
Stefano On BEST ANSWER

The problem is not in docker-compose but in the mockserver image. Since it's executed without root rights, it cannot use the port 80 but it starts always on the port 1080 (check https://www.mock-server.com/where/docker.html#run_docker_container for more info).

You can change the port by starting the docker image using this:

docker run --rm --name mockserver mockserver/mockserver -serverPort 1090

which will let you have the image running on port 1090 (which is not what you want) or you can do force the container to run as root and change the port to 80. e.g.

docker run --user root --rm --name mockserver mockserver/mockserver -serverPort 80

Anyway there might be good reasons not to use root for this. I've never used this software so I can't really say.

You can then easily port the command in docker-compose format

0
nTOXIC On

This setup works great, especially with forwarding requests with mockserver:

nginx-vhosts:

server {
    listen 80 default;

    location / {
        return 418;
    }
}

server {
    listen 443 ssl;

    ssl_certificate /etc/ssl/certs/local.pub.pem;
    ssl_certificate_key /etc/ssl/private/local.key.pem;
    ssl_session_cache shared:SSL:16m;
    ssl_session_timeout 10m;
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers RC4:HIGH:!aNULL:!MD5:!kEDH;
    ssl_prefer_server_ciphers on;

    location / {
        return 418;
    }
}

docker-compose.yml

version: '3.8'

services:
  nginx:
    build:
      context: .
      dockerfile: docker/nginx/Dockerfile
    networks:
      - our-network

  busybox:
    image: yauritux/busybox-curl:latest
    command: tail -f /dev/null
    networks:
      - our-network

  api-mock: *api-mock
    image: mockserver/mockserver
    user: root
    command: -serverPort 80
    networks:
      our-network:
        aliases:
          - oauth2.googleapis.com
    environment:
      MOCKSERVER_INITIALIZATION_JSON_PATH: /api-mock/expectations_init.json
      MOCKSERVER_WATCH_INITIALIZATION_JSON: 'true'
    volumes:
      - ./api-mock/:/api-mock
    ports:
      - 1080:80

  api-mock-secure:
    <<: *api-mock
    command: -serverPort 443
    ports:
      - 1081:443

networks:
  our-network:

expectations_init.json

[
  {
    "httpRequest": {
      "method": "GET",
      "path": "/token",
      "headers": {
        "Host": [ "oauth2.googleapis.com" ]
      },
      "secure": true
    },
    "httpResponse": {
      "statusCode": 200,
      "body": "Hello World - secure\n"
    }
  },
  {
    "httpRequest": {
      "method": "GET",
      "path": "/token",
      "headers": {
        "Host": [ "oauth2.googleapis.com" ]
      },
      "secure": false
    },
    "httpResponse": {
      "statusCode": 200,
      "body": "Hello World\n"
    }
  },
  {
    "httpRequest": {
      "secure": false
    },
    "httpForward": {
      "host": "nginx",
      "port": 80,
      "scheme": "HTTP"
    }
  },
  {
    "httpRequest": {
      "secure": true
    },
    "httpForward": {
      "host": "nginx",
      "port": 443,
      "scheme": "HTTPS"
    }
  }
]

Thanks to Stefano