3

I'm setting a secure configuration with Keycloak and Kong for an angular API.

I was following the next tutorial https://www.jerney.io/secure-apis-kong-keycloak-1/ , but at the end I'm getting the next error:

Access to XMLHttpRequest at 'http‍://localhost:8000/ops/warehouses' from origin 'http‍://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.

I have an angular API that connects to a backend API in typescript. So what I want is to secure the whole API back and front using Keycloak.

I'm using Kong as an API gateway and Konga as an interface for administrate Kong.

The integration of keycloak with Kong is through a plugin OIDC https://github.com/nokia/kong-oidc

My current Keycloak version is 6.0.1, the Kong version is 1.2.1 and Konga 0.14.3. And i'm deploying each one of these elements into containers using Docker.

My angular application is using npm install keycloak-js --save and i follow the next configuration https://medium.com/@blained3/connecting-keycloak-to-angular-d175c92a0dd3


This is the docker compose configuration:

//docker-compose.yml

version: '3.4'

networks: 
  kong_network:

volumes:
  kong-datastore:
  keycloak-datastore:

services:
  kong-db:
    image: postgres:9.6
    restart: always
    volumes:
      - kong-datastore:/var/lib/postgresql/data
    networks:
      - kong_network
    ports:
      - "15432:5432"
    environment:
      POSTGRES_DB:       kong
      POSTGRES_USER:     kong
      POSTGRES_PASSWORD:
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "kong"]
      interval: 5s
      timeout: 5s
      retries: 5

  kong-migration:
    build: .
    command: "kong migrations bootstrap"
    networks:
      - kong_network
    restart: on-failure
    environment:
      KONG_PG_HOST: kong-db
    links:
      - kong-db
    depends_on:
      - kong-db

  kong:
    build: .
    restart: always
    depends_on:
      - kong-migration
      - kong-db
    healthcheck:
      test: ["CMD", "curl", "-f", "http://kong:8001"]
      interval: 5s
      timeout: 2s
      retries: 15
    networks:
      - kong_network
    ports:
      - "8000:8000" # Listener
      - "8001:8001" # Admin API
      - "8443:8443" # Listener  (SSL)
      - "8444:8444" # Admin API (SSL)
    extra_hosts:
      - "keycloak-host:192.168.18.247"
    environment:
      KONG_DATABASE:         postgres
      KONG_PG_HOST:          kong-db
      KONG_PG_PORT:          5432
      KONG_PG_DATABASE:      kong
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG:  /dev/stderr
      KONG_ADMIN_ERROR_LOG:  /dev/stderr
      KONG_PROXY_LISTEN:     0.0.0.0:8000, 0.0.0.0:8443 ssl
      KONG_ADMIN_LISTEN:     0.0.0.0:8001, 0.0.0.0:8444 ssl
      KONG_PLUGINS:          oidc

  keycloak-db:
    image: postgres:9.6
    volumes: 
      - keycloak-datastore:/var/lib/postresql/data
    networks:
      - kong_network
    ports:
      - "25432:5432"
    environment:
      POSTGRES_DB:       keycloak
      POSTGRES_USER:     keycloak
      POSTGRES_PASSWORD: password

  keycloak:
    image: jboss/keycloak:4.5.0.Final
    restart: always
    depends_on:
      - keycloak-db
    networks:
      - kong_network
    ports:
      - "8180:8080"
    environment:
      DB_VENDOR:   POSTGRES
      DB_ADDR:     keycloak-db
      DB_PORT:     5432
      DB_DATABASE: keycloak
      DB_USER:     keycloak
      DB_PASSWORD: password
      KEYCLOAK_USER:     admin
      KEYCLOAK_PASSWORD: admin

//Dockerfile

 FROM kong:1.1.2-alpine
 RUN apk update && apk add git unzip curl
 ENV KONG_PLUGINS="bundled, oidc"
 RUN luarocks install kong-oidc

//Kong configuration through Konga

Konga is running at port 1337 Kong admin at 8001 and client Kong at 8000

So what I did was to create a service with the next configuration:

{
  "host": "192.168.18.247",
  "created_at": 1565303126,
  "connect_timeout": 60000,
  "id": "376ef70a-87af-43ba-92c2-a5d459ccac4f",
  "protocol": "http",
  "name": "ops",
  "read_timeout": 60000,
  "port": 3000,
  "path": "/api",
  "updated_at": 1565303147,
  "retries": 5,
  "write_timeout": 60000,
  "tags": null,
  "extras": {
    "createdUser": null,
    "updatedUser": null,
    "kong_node_id": "1",
    "service_id": "376ef70a-87af-43ba-92c2-a5d459ccac4f",
    "createdAt": "2019-08-08T22:25:26.319Z",
    "updatedAt": "2019-08-08T22:25:47.349Z",
    "id": 1
  }
}

to this service I added the next route:

{
  "updated_at": 1565303167,
  "created_at": 1565303167,
  "strip_path": true,
  "snis": null,
  "hosts": null,
  "name": "ops",
  "methods": null,
  "sources": null,
  "preserve_host": false,
  "regex_priority": 0,
  "service": {
    "host": "192.168.18.247",
    "created_at": 1565303126,
    "connect_timeout": 60000,
    "id": "376ef70a-87af-43ba-92c2-a5d459ccac4f",
    "protocol": "http",
    "name": "ops",
    "read_timeout": 60000,
    "port": 3000,
    "path": "/api",
    "updated_at": 1565303147,
    "retries": 5,
    "write_timeout": 60000,
    "tags": null,
    "extras": {
      "createdUser": null,
      "updatedUser": null,
      "kong_node_id": "1",
      "service_id": "376ef70a-87af-43ba-92c2-a5d459ccac4f",
      "createdAt": "2019-08-08T22:25:26.319Z",
      "updatedAt": "2019-08-08T22:25:47.349Z",
      "id": 1
    }
  },
  "paths": [
    "/ops"
  ],
  "destinations": null,
  "id": "1e0ba28b-da93-44d1-9433-ea2bf03340d6",
  "protocols": [
    "http",
    "https"
  ],
  "tags": null
}

My plugin OIDC:

{
  "created_at": 1564164342,
  "config": {
    "response_type": "code",
    "introspection_endpoint": "http://keycloak-host:8180/auth/realms/master/protocol/openid-connect/token/introspect",
    "filters": null,
    "bearer_only": "true",
    "ssl_verify": "no",
    "session_secret": null,
    "introspection_endpoint_auth_method": null,
    "realm": "master",
    "redirect_after_logout_uri": "/",
    "scope": "openid",
    "token_endpoint_auth_method": "client_secret_post",
    "logout_path": "/logout",
    "client_id": "back",
    "client_secret": "b1f34901-becc-4f6a-a586-258fef04569c",
    "discovery": "http://keycloak-host:8180/auth/realms/master/.well-known/openid-configuration",
    "recovery_page_path": null,
    "redirect_uri_path": null
  },
  "id": "bc77d4d7-9fdb-4267-8997-a8187c182ecc",
  "service": null,
  "name": "oidc",
  "protocols": [
    "http",
    "https"
  ],
  "enabled": true,
  "run_on": "first",
  "consumer": null,
  "route": null,
  "tags": null
}


My configuration in Keycloak is the next one:

I've created two clients, one for the frontend and the other one for my frontend.

//FRONT

{
  "realm": "MyDemo",
  "auth-server-url": "http://localhost:8180/auth",
  "ssl-required": "external",
  "resource": "front",
  "public-client": true,
  "confidential-port": 0
}

//BACK

   {
     "realm": "MyDemo",
     "bearer-only": true,
     "auth-server-url": "http://localhost:8180/auth",
     "ssl-required": "external",
     "resource": "back",
     "credentials": {
     "secret": "20f3bcf1-683d-4e1c-98a6-414877e461db"
      },
     "confidential-port": 0,
     "policy-enforcer": {}
   }

In my frontend in angular I have configured my url to the backend:

    export const API = {
      'uri': 'http://localhost:8000/ops/'
    };

And I have created two files to manage the keycloak service:

//keycloak.service.ts

import { Injectable } from '@angular/core';
declare var Keycloak: any;
@Injectable({
 providedIn: 'root'
})
export class KeycloakService {
 public keycloakAuth: any;
 constructor() { }
 init(): Promise<any> {
 return new Promise((resolve, reject) => {
 const config = {

 'url': 'http://keycloak-host:8180/auth',
 'realm': 'master',
 'clientId': 'front',
 'credentials': {
     'secret': 'd030874e-41bc-4710-b28f-c568e7e66c66'
   },
 };
 this.keycloakAuth = new Keycloak(config);
 this.keycloakAuth.init({ onLoad: 'login-required' })
 .success(() => {
 resolve();
 })
 .error(() => {
 reject();
 });
 });
 }

 getToken(): string {
 return this.keycloakAuth.token;
 }
}

//token.interceptor.ts

import { Injectable } from '@angular/core';
import {
 HttpRequest,
 HttpHandler,
 HttpEvent,
 HttpInterceptor,
 HttpHeaders
} from '@angular/common/http';
import { KeycloakService } from './keycloak.service';
import { Observable } from 'rxjs';

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

 constructor(private kcService: KeycloakService) {}

 intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
 console.log("BIngo!!!!!!!!!");
 const authToken = this.kcService.getToken() || '';
 request = request.clone({
 // setHeaders: {
 // 'Authorization': 'Bearer ' + authToken
 // }
 headers: new HttpHeaders({
 'Content-Type': 'application/json',
 'Authorization': 'Bearer ' + authToken
 })

 });
 console.log(authToken);
 return next.handle(request);
 }
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • The error suggests that you are missing a certain parameter in your request headers. This article may help you - http://restlet.com/company/blog/2015/12/15/understanding-and-using-cors/ – M M Aug 12 '19 at 06:28

0 Answers0