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

Refactor outbound authentication with custom providers and handlers #15696

Merged

Conversation

ldclakmal
Copy link
Member

@ldclakmal ldclakmal commented Jun 12, 2019

Purpose

This PR provides the capability of custom authentication providers and handlers engagement for outbound authentication. The current design of HTTP outbound authentication is not extensible. Also, it creates cyclic dependencies, in future (ex: When adding JWKs support). And the user cannot attach a custom provider and handler because the authentication mechanisms and their related logic are tightly coupled with the http_secure_client of Ballerina.

This is a similar approach done at refactoring inbound authentication with custom providers and handlers by #15056.

Refer the email discussion @ ballerina-dev [1] for more information.
[1] https://groups.google.com/d/msg/ballerina-dev/OvlUscsjT-I/VmTTBg-DBAAJ

Fixes #15487

Approach

  • ballerina/auth module provides an abstract object named OutboundAuthProvider, which is responsible for the following 2 actions:
    • generateToken() - Generate the token that is used to authenticate with the external endpoint
    • inspect(map<anydata> data) - Inspect the received map of data from outbound authentication
  • auth:OutboundBasicAuthProvider, jwt:OutboundJwtAuthProvider and oauth2:OutboundOAuth2Provider are implementations of the auth:OutboundAuthProvider for different authentication mechanisms.

  • ballerina/http module provides an abstract object named OutboundAuthnHandler, which is responsible for the following 2 actions:
    • prepare(http:Request req) - Prepare the HTTP request for outbound authentication
    • inspect(http:Request req, http:Response resp) - Inspect the received HTTP request and response from outbound authentication
  • http:BasicAuthHandler and http:BearerAuthHandler are implementations of the http:OutboundAuthHandler for different use cases.

If a user wants to engage a custom authentication logic, it is needed to write an outbound custom auth provider and outbound custom auth handler as follows. Or else already implemented handlers and providers can be used.

Outbound Custom Auth Provider

import ballerina/auth;

public type OutboundCustomAuthProvider object {

    *auth:OutboundAuthProvider;

    public function generateToken() returns string|error {
        // Logic related to generating the tokens for outbound authentication
    }

    public function inspect(map<anydata> data) returns string|error? {
        // Logic related to inspect the provided the tokens for outbound authentication
    }
}

Outbound Custom Auth Handler

import ballerina/auth;
import ballerina/http;

public type OutboundCustomAuthHandler object {

    *http:OutboundAuthHandler;

    public auth:OutboundAuthProvider authProvider;

    public function __init(auth:OutboundAuthProvider authProvider) {
        self.authProvider = authProvider;
    }

    public function prepare(Request req) returns Request|error {
        // Logic related to preparing the provided HTTP request for outbound authentication
    }

    public function inspect(Request req, Response resp) returns Request|error? {
        // Logic related to inspection of received HTTP request and response from outbound authentication
    }
};

Samples

Sample 1 - Outbound authentication with Basic Auth

import ballerina/auth;
import ballerina/http;

auth:OutboundBasicAuthProvider basicAuthProvider = new({ username: "tom", password: "123" });
http:BasicAuthHandler basicAuthHandler = new(basicAuthProvider);

http:Client nyseEP = new("https://localhost:9090", config = {
    auth: {
        authHandler: basicAuthHandler
    }
});

Sample 2 - Outbound authentication with JWT Auth

import ballerina/http;
import ballerina/jwt;

jwt:OutboundJwtAuthProvider jwtAuthProvider = new({
        issuer: "ballerina",
        audience: ["ballerina"],
        issuerConfig: {
            keyAlias: "ballerina",
            keyPassword: "ballerina",
            keyStore: {
                path: "${ballerina.home}/bre/security/ballerinaKeystore.p12",
                password: "ballerina"
            }
        }
    }
});
http:BearerAuthHandler jwtAuthHandler = new(jwtAuthProvider);

http:Client nyseEP = new("https://localhost:9090", config = {
    auth: {
        authHandler: jwtAuthHandler
    }
});

Sample 3 - Outbound authentication with OAuth2

import ballerina/http;
import ballerina/oauth2;

oauth2:OutboundOAuth2Provider oauth2Provider = new({
    tokenUrl: "https://localhost:9196/oauth2/token",
    clientId: "3MVG9YDQS5WtC11paU",
    clientSecret: "92053723741"
});
http:BearerAuthHeaderHandler oauth2Handler = new(oauth2Provider);

http:Client nyseEP = new("https://localhost:9090", config = {
    auth: {
        authHandler: oauth2Handler
    }
});

Sample 4 - Outbound authentication with Custom Auth

This is a sample program which handles authentication with authorization with a custom header.

sample.bal

import ballerina/http;

OutboundCustomAuthProvider customAuthProvider = new;
OutboundCustomAuthHandler customAuthHandler = new(customAuthProvider);

http:Client nyseEP = new("https://localhost:9090", config = {
    auth: {
        authHandler: customAuthHandler
    }
});

outbound_custom_auth_provider.bal

import ballerina/auth;

public type OutboundCustomAuthProvider object {

    *auth:OutboundAuthProvider;

    public function generateToken() returns string|error {
        return "sUA4M8A!k7pU";
    }

    public function inspect(map<anydata> data) returns string|error? {
        return ();
    }
}

outbound_custom_auth_handler.bal

import ballerina/auth;
import ballerina/http;

public type OutboundCustomAuthHandler object {

    *http:OutboundAuthHandler;

    public OutboundCustomAuthProvider authProvider;

    public function __init(OutboundCustomAuthProvider authProvider) {
        self.authProvider = authProvider;
    }

    public function prepare(Request req) returns Request|error {
        string token = chekc self.authProvider.generateToken();
        req.addHeader("Authorization", token);
        return req;
    }

    public function inspect(Request req, Response resp) returns Request|error? {
        self.authProvider.inspect(new);
    }
};

Check List

  • Read the Contributing Guide
  • Required Balo version update
  • Updated Change Log
  • Checked Tooling Support (#)
  • Added necessary tests
    • Unit Tests
    • Spec Conformance Tests
    • Integration Tests
    • Ballerina By Example Tests
  • Increased Test Coverage
  • Added necessary documentation
    • API documentation
    • Module documentation in Module.md files
    • Ballerina By Examples

ldclakmal added 30 commits June 2, 2019 19:44
…ina-lang into refactor-outbound-auth

# Conflicts:
#	stdlib/http/src/main/ballerina/http/client_endpoint.bal
#	stdlib/http/src/main/ballerina/http/http_secure_client.bal
#	tests/ballerina-integration-test/src/test/resources/auth/authservices/11_token_propagation_basic_auth_test.bal
#	tests/ballerina-integration-test/src/test/resources/auth/authservices/12_token_propagation_jwt_test.bal
#	tests/ballerina-integration-test/src/test/resources/auth/authservices/13_token_propagation_jwt_reissuing_test.bal
#	tests/ballerina-integration-test/src/test/resources/auth/authservices/14_token_propagation_jwt_reissuing_negative_test.bal
@ldclakmal ldclakmal changed the base branch from master to jballerina June 19, 2019 08:48
stdlib/auth/src/main/ballerina/auth/Module.md Outdated Show resolved Hide resolved
stdlib/auth/src/main/ballerina/auth/Module.md Outdated Show resolved Hide resolved
stdlib/auth/src/main/ballerina/auth/Module.md Outdated Show resolved Hide resolved
stdlib/auth/src/main/ballerina/auth/Module.md Outdated Show resolved Hide resolved
stdlib/auth/src/main/ballerina/auth/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/Module.md Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/annotation.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/auth/utils.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/service_endpoint.bal Outdated Show resolved Hide resolved
stdlib/http/src/main/ballerina/http/service_endpoint.bal Outdated Show resolved Hide resolved
stdlib/oauth2/src/main/ballerina/oauth2/Module.md Outdated Show resolved Hide resolved
stdlib/oauth2/src/main/ballerina/oauth2/Module.md Outdated Show resolved Hide resolved
ldclakmal and others added 5 commits June 21, 2019 15:05
…llerina-lang into refactor-outbound-auth

# Conflicts:
#	stdlib/ldap/src/main/java/org/ballerinalang/stdlib/ldap/nativeimpl/InitLdapConnectionContext.java
@ldclakmal ldclakmal requested a review from wggihan June 21, 2019 11:12
@ldclakmal ldclakmal merged commit f0b0ab7 into ballerina-platform:jballerina Jun 25, 2019
@ldclakmal ldclakmal deleted the refactor-outbound-auth branch March 27, 2020 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Team/StandardLibs All Ballerina standard libraries Type/Improvement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants