LIGHT

  • News
  • Docs
  • Community
  • Reddit
  • GitHub

Enable Security

In previous steps, we have explored all different options of service discovery. In this step, we are going to build on top of http-health codebase and enable the security with light-oauth2. It is requested by some users who want to see how different features work together in a distributed application.

Start Consul

docker run -d -p 8400:8400 -p 8500:8500/tcp -p 8600:53/udp -e 'CONSUL_LOCAL_CONFIG={"acl_datacenter":"dc1","acl_default_policy":"allow","acl_down_policy":"extend-cache","acl_master_token":"the_one_ring","bootstrap_expect":1,"datacenter":"dc1","data_dir":"/usr/local/bin/consul.d/data","server":true}' consul agent -server -ui -bind=127.0.0.1 -client=0.0.0.0

Start light-oauth2

The default security for light-4j is OAuth 2.0 and light-oauth2 is an implementation of a set of microservices. It is very easy to start it with the docker-compose in light-docker repository.

If you haven’t checked out the light-docker, you can.

cd ~/networknt
git clone https://github.com/networknt/light-docker.git

Make sure you have Docker installed on your desktop or test server. Start the light-oauth2 with the following command.

cd ~/networknt/light-docker
docker-compose -f docker-compose-oauth2-mysql.yml up -d

Client Registration

Since we have API A calls API B, API C and API B calls API D, we need to register API B to the light-oauth2 to get scope token to the next API D. When we call the API A, we can use the long-lived token. We can register the API B as a client by accessing the API from curl. For more information about light-oauth2, please check the light-oauth2 tutorial.

API D needs scope ad.r or ad.w to access the endpoint, so we need to make the API B client registrion like the following.

curl -k -H "Content-Type: application/json" -X POST -d '{"clientType":"public","clientProfile":"mobile","clientName":"API B","clientDesc":"API B","scope":"ad.r ad.w","redirectUri": "http://localhost:8080/authorization","ownerId":"admin"}' https://localhost:6884/oauth2/client

The return result contains the generated client_id and client_secret we need in the API B client.yml configuration later on.

{"clientId":"2cf4d072-f53a-46e8-b710-037fabcba4f3","clientSecret":"sRFRUmjJRZ-Zpq15CC9u7g","clientType":"public","clientProfile":"mobile","clientName":"API B","clientDesc":"API B","ownerId":"admin","scope":"ad.r ad.w","customClaim":null,"redirectUri":"http://localhost:8080/authorization","authenticateClass":null,"derefClientId":null}

API A is calling API B and API C, so we need to register it on the light-oauth2 as a client. It needs to have access to scope ab.r and ac.r

curl -k -H "Content-Type: application/json" -X POST -d '{"clientType":"public","clientProfile":"mobile","clientName":"API A","clientDesc":"API A","scope":"ab.r ac.r","redirectUri": "http://localhost:8080/authorization","ownerId":"admin"}' https://localhost:6884/oauth2/client

The returned result will be used to config the client.yml for API A.

{"clientId":"f10ab624-16b5-4355-8b7a-aa4b37351855","clientSecret":"kve4koSJR1S83ho4tcaOiQ","clientType":"public","clientProfile":"mobile","clientName":"API A","clientDesc":"API A","ownerId":"admin","scope":"ab.r ac.r","customClaim":null,"redirectUri":"http://localhost:8080/authorization","authenticateClass":null,"derefClientId":null}

Create security folder

Let’s copy from http-health to security for each API.

cd ~/networknt/light-example-4j/discovery/api_a
cp -r http-health security
cd ~/networknt/light-example-4j/discovery/api_b
cp -r http-health security
cd ~/networknt/light-example-4j/discovery/api_c
cp -r http-health security
cd ~/networknt/light-example-4j/discovery/api_d
cp -r http-health security

API D

After we copy the folders, we need to update these APIs.

We need to change the consulUrl to point to the local consul server with http.

consul.yml

# Consul URL for accessing APIs
consulUrl: http://localhost:8500
# access token to the consul server
consulToken: the_one_ring
# number of requests before reset the shared connection.
maxReqPerConn: 1000000
# deregister the service after the amount of time after health check failed.
deregisterAfter: 2m
# health check interval for TCP or HTTP check. Or it will be the TTL for TTL check. Every 10 seconds,
# TCP or HTTP check request will be sent. Or if there is no heart beat request from service after 10 seconds,
# then mark the service is critical.
checkInterval: 10s
# One of the following health check approach will be selected. Two passive (TCP and HTTP) and one active (TTL)
# enable health check TCP. Ping the IP/port to ensure that the service is up. This should be used for most of
# the services with simple dependencies. If the port is open on the address, it indicates that the service is up.
tcpCheck: false
# enable health check HTTP. A http get request will be sent to the service to ensure that 200 response status is
# coming back. This is suitable for service that depending on database or other infrastructure services. You should
# implement a customized health check handler that checks dependencies. i.e. if db is down, return status 400.
httpCheck: true
# enable health check TTL. When this is enabled, Consul won't actively check your service to ensure it is healthy,
# but your service will call check endpoint with heart beat to indicate it is alive. This requires that the service
# is built on top of light-4j and the above options are not available. For example, your service is behind NAT.
ttlCheck: false
# endpoints that support blocking will also honor a wait parameter specifying a maximum duration for the blocking request.
# This is limited to 10 minutes.This value can be specified in the form of "10s" or "5m" (i.e., 10 seconds or 5 minutes,
# respectively).
wait: 600s
# enable HTTP/2, HTTP/2 used to be default but some users said that newer version of Consul doesn't support HTTP/2 anymore.
enableHttp2: false

Enable security

openapi-security.yml

enableVerifyJwt: true

Update server.yml to ensure that dynamicPort is false.

dynamicPort: false

API C

API C will be called by API A and it won’t call any other API. We need to simply enable the security.

openapi-security.yml

# Security configuration for openapi-security in light-rest-4j. It is a specific config
# for OpenAPI framework security. It is introduced to support multiple frameworks in the
# same server instance. If this file cannot be found, the generic security.yml will be
# loaded for backward compatibility.
---
# Enable JWT verification flag.
enableVerifyJwt: true

# Enable JWT scope verification. Only valid when enableVerifyJwt is true.
enableVerifyScope: true

# User for test only. should be always be false on official environment.
enableMockJwt: false

# JWT signature public certificates. kid and certificate path mappings.
jwt:
  certificate:
    '100': primary.crt
    '101': secondary.crt
  clockSkewInSeconds: 60

# Enable or disable JWT token logging
logJwtToken: true

# Enable or disable client_id, user_id and scope logging.
logClientUserScope: false

# Enable JWT token cache to speed up verification. This will only verify expired time
# and skip the signature verification as it takes more CPU power and long time.
enableJwtCache: true

# If you are using light-oauth2, then you don't need to have oauth subfolder for public
# key certificate to verify JWT token, the key will be retrieved from key endpoint once
# the first token is arrived. Default to false for dev environment without oauth2 server
# or official environment that use other OAuth 2.0 providers.
bootstrapFromKeyService: false

update consulUrl and consulToken in consul.yml

# Consul URL for accessing APIs
consulUrl: http://localhost:8500
# access token to the consul server
consulToken: the_one_ring

Update server.yml to ensure that dynamicPort is false.

dynamicPort: false

API B

For API B, we need to update client.yml for the client_id and client_secret genreated in the previous step during the client registration of light-oauth2.

Here is the updated section in client.yml for the client_credentials grant flow.

    client_credentials:
      # token endpoint for client credentials grant
      uri: "/oauth2/token"
      # client_id for client credentials grant flow. client_secret is in secret.yml
      client_id: 2cf4d072-f53a-46e8-b710-037fabcba4f3
      # client_secret for client credentials grant flow.
      client_secret: sRFRUmjJRZ-Zpq15CC9u7g
      # optional scope, default scope in the client registration will be used if not defined.
      scope:
      - ad.r
      - ad.w

Next we need to update the openapi-security.yml for API B to enable security.

openapi-security.yml

# Security configuration for openapi-security in light-rest-4j. It is a specific config
# for OpenAPI framework security. It is introduced to support multiple frameworks in the
# same server instance. If this file cannot be found, the generic security.yml will be
# loaded for backward compatibility.
---
# Enable JWT verification flag.
enableVerifyJwt: true

# Enable JWT scope verification. Only valid when enableVerifyJwt is true.
enableVerifyScope: true

# User for test only. should be always be false on official environment.
enableMockJwt: false

# JWT signature public certificates. kid and certificate path mappings.
jwt:
  certificate:
    '100': primary.crt
    '101': secondary.crt
  clockSkewInSeconds: 60

# Enable or disable JWT token logging
logJwtToken: true

# Enable or disable client_id, user_id and scope logging.
logClientUserScope: false

# Enable JWT token cache to speed up verification. This will only verify expired time
# and skip the signature verification as it takes more CPU power and long time.
enableJwtCache: true

# If you are using light-oauth2, then you don't need to have oauth subfolder for public
# key certificate to verify JWT token, the key will be retrieved from key endpoint once
# the first token is arrived. Default to false for dev environment without oauth2 server
# or official environment that use other OAuth 2.0 providers.
bootstrapFromKeyService: false

update consulUrl and consulToken in consul.yml

# Consul URL for accessing APIs
consulUrl: http://localhost:8500
# access token to the consul server
consulToken: the_one_ring

Update server.yml to ensure that dynamicPort is false.

dynamicPort: false

API A

Update openapi-security to enable security first. In order to use the long-lived token to access API A with curl, we are going to disable the scope verfication in the openapi-security.yml

# Enable JWT verification flag.
enableVerifyJwt: true

# Enable JWT scope verification. Only valid when enableVerifyJwt is true.
enableVerifyScope: false

And then update the client.yml for the client_credentials section with the client_id and client_secret returned from light-oauth2 registration.

    client_credentials:
      # token endpoint for client credentials grant
      uri: "/oauth2/token"
      # client_id for client credentials grant flow. client_secret is in secret.yml
      client_id: f10ab624-16b5-4355-8b7a-aa4b37351855
      # client_secret for client credentials grant flow.
      client_secret: kve4koSJR1S83ho4tcaOiQ
      # optional scope, default scope in the client registration will be used if not defined.
      scope:
      - ab.r
      - ac.r

update consulUrl and consulToken in consul.yml

# Consul URL for accessing APIs
consulUrl: http://localhost:8500
# access token to the consul server
consulToken: the_one_ring

Update server.yml to ensure that dynamicPort is false.

dynamicPort: false

Starting the servers

Now let’s start four terminals to start servers.

API A

cd ~/networknt/light-example-4j/discovery/api_a/security
mvn clean install -Prelease
java -jar target/aa-1.0.0.jar

API B

cd ~/networknt/light-example-4j/discovery/api_b/security
mvn clean install -Prelease
java -jar target/ab-1.0.0.jar

API C

cd ~/networknt/light-example-4j/discovery/api_c/security
mvn clean install -Prelease
java -jar target/ac-1.0.0.jar

API D

And start the first instance that listen to 7445 as default

cd ~/networknt/light-example-4j/discovery/api_d/security
mvn clean install -Prelease
java -jar target/ad-1.0.0.jar

Test

We can test the services with the following curl command.

curl -k https://localhost:7441/v1/data \
  -H 'Authorization: Bearer eyJraWQiOiIxMDAiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ1cm46Y29tOm5ldHdvcmtudDpvYXV0aDI6djEiLCJhdWQiOiJ1cm46Y29tLm5ldHdvcmtudCIsImV4cCI6MTc5MDAzNTcwOSwianRpIjoiSTJnSmdBSHN6NzJEV2JWdUFMdUU2QSIsImlhdCI6MTQ3NDY3NTcwOSwibmJmIjoxNDc0Njc1NTg5LCJ2ZXJzaW9uIjoiMS4wIiwidXNlcl9pZCI6InN0ZXZlIiwidXNlcl90eXBlIjoiRU1QTE9ZRUUiLCJjbGllbnRfaWQiOiJmN2Q0MjM0OC1jNjQ3LTRlZmItYTUyZC00YzU3ODc0MjFlNzIiLCJzY29wZSI6WyJ3cml0ZTpwZXRzIiwicmVhZDpwZXRzIl19.mue6eh70kGS3Nt2BCYz7ViqwO7lh_4JSFwcHYdJMY6VfgKTHhsIGKq2uEDt3zwT56JFAePwAxENMGUTGvgceVneQzyfQsJeVGbqw55E9IfM_uSM-YcHwTfR7eSLExN4pbqzVDI353sSOvXxA98ZtJlUZKgXNE1Ngun3XFORCRIB_eH8B0FY_nT_D1Dq2WJrR-re-fbR6_va95vwoUdCofLRa4IpDfXXx19ZlAtfiVO44nw6CS8O87eGfAm7rCMZIzkWlCOFWjNHnCeRsh7CVdEH34LF-B48beiG5lM7h4N12-EME8_VDefgMjZ8eqs1ICvJMxdIut58oYbdnkwTjkA' \
  -H 'Content-Type: application/json'

And the following result is expected.

["API D: Message 1 from port 7444","API D: Message 2 from port 7444","API B: Message 1","API B: Message 2","API C: Message 1","API C: Message 2","API A: Message 1","API A: Message 2"]

With the security enabled, the client module is propagating the original token, traceabilityId and correlationId to the entire chain of the call tree. In the next tutorial, we are going to replace the traceability and correlation handlers with OpenTracing.

  • About Light
    • Overview
    • Testimonials
    • What is Light
    • Features
    • Principles
    • Benefits
    • Roadmap
    • Community
    • Articles
    • Videos
    • License
    • Why Light Platform
  • Getting Started
    • Get Started Overview
    • Environment
    • Light Codegen Tool
    • Light Rest 4j
    • Light Tram 4j
    • Light Graphql 4j
    • Light Hybrid 4j
    • Light Eventuate 4j
    • Light Oauth2
    • Light Portal Service
    • Light Proxy Server
    • Light Router Server
    • Light Config Server
    • Light Saga 4j
    • Light Session 4j
    • Webserver
    • Websocket
    • Spring Boot Servlet
  • Architecture
    • Architecture Overview
    • API Category
    • API Gateway
    • Architecture Patterns
    • CQRS
    • Eco System
    • Event Sourcing
    • Fail Fast vs Fail Slow
    • Integration Patterns
    • JavaEE declining
    • Key Distribution
    • Microservices Architecture
    • Microservices Monitoring
    • Microservices Security
    • Microservices Traceability
    • Modular Monolith
    • Platform Ecosystem
    • Plugin Architecture
    • Scalability and Performance
    • Serverless
    • Service Collaboration
    • Service Mesh
    • SOA
    • Spring is bloated
    • Stages of API Adoption
    • Transaction Management
    • Microservices Cross-cutting Concerns Options
    • Service Mesh Plus
    • Service Discovery
  • Design
    • Design Overview
    • Design First vs Code First
    • Desgin Pattern
    • Service Evolution
    • Consumer Contract and Consumer Driven Contract
    • Handling Partial Failure
    • Idempotency
    • Server Life Cycle
    • Environment Segregation
    • Database
    • Decomposition Patterns
    • Http2
    • Test Driven
    • Multi-Tenancy
    • Why check token expiration
    • WebServices to Microservices
  • Cross-Cutting Concerns
    • Concerns Overview
  • API Styles
    • Light-4j for absolute performance
    • Style Overview
    • Distributed session on IMDG
    • Hybrid Serverless Modularized Monolithic
    • Kafka - Event Sourcing and CQRS
    • REST - Representational state transfer
    • Web Server with Light
    • Websocket with Light
    • Spring Boot Integration
    • Single Page Application
    • GraphQL - A query language for your API
    • Light IBM MQ
    • Light AWS Lambda
    • Chaos Monkey
  • Infrastructure Services
    • Service Overview
    • Light Proxy
    • Light Mesh
    • Light Router
    • Light Portal
    • Messaging Infrastructure
    • Centralized Logging
    • COVID-19
    • Light OAuth2
    • Metrics and Alerts
    • Config Server
    • Tokenization
    • Light Controller
  • Tool Chain
    • Tool Chain Overview
  • Utility Library
  • Service Consumer
    • Service Consumer
  • Development
    • Development Overview
  • Deployment
    • Deployment Overview
    • Frontend Backend
    • Linux Service
    • Windows Service
    • Install Eventuate on Windows
    • Secure API
    • Client vs light-router
    • Memory Limit
    • Deploy to Kubernetes
  • Benchmark
    • Benchmark Overview
  • Tutorial
    • Tutorial Overview
  • Troubleshooting
    • Troubleshoot
  • FAQ
    • FAQ Overview
  • Milestones
  • Contribute
    • Contribute to Light
    • Development
    • Documentation
    • Example
    • Tutorial
“Enable Security” was last updated: July 5, 2021: fixes #275 checked and corrected grammar/spelling for majority of pages (#276) (b3bbb7b)
Improve this page
  • News
  • Docs
  • Community
  • Reddit
  • GitHub
  • About Light
  • Getting Started
  • Architecture
  • Design
  • Cross-Cutting Concerns
  • API Styles
  • Infrastructure Services
  • Tool Chain
  • Utility Library
  • Service Consumer
  • Development
  • Deployment
  • Benchmark
  • Tutorial
  • Troubleshooting
  • FAQ
  • Milestones
  • Contribute