import ballerina/auth;
import ballerina/config;
import ballerina/http;
import ballerina/log;
auth:InboundBasicAuthProvider basicAuthProvider = new;
http:BasicAuthHandler basicAuthHandler = new (basicAuthProvider);
listener http:Listener ep = new (9090, config = {
    auth: {
        authHandlers: [basicAuthHandler]
    },
    secureSocket: {
        keyStore: {
            path: config:getAsString("b7a.home") +
                  "/bre/security/ballerinaKeystore.p12",
            password: "ballerina"
        }
    }
});@http:ServiceConfig {
    basePath: "/hello",
    auth: {
        scopes: ["scope1"]
    }
}
service echo on ep {    @http:ResourceConfig {
        methods: ["GET"],
        path: "/sayHello",
        auth: {
            scopes: ["scope2"]
        }
    }
    resource function hello(http:Caller caller, http:Request req) {
        error? result = caller->respond("Hello, World!!!");
        if (result is error) {
            log:printError("Error in responding to caller", result);
        }
    }
}# At the command line, navigate to the directory that contains the `.bal` file.
# Ensure that the `sample-users.toml` file is populated correctly with the user
# information. If required, user passwords can be encrypted using the
# `ballerina encrypt` configuration encryption command.
echo '["b7a.users"]
["b7a.users.alice"]
password="password1"
scopes="scope1"
["b7a.users.bob"]
password="password2"
scopes="scope2,scope3"' > sample-users.toml# To run the service, execute the below command by specifying the configuration
# file name and passing Ballerina home path as a system property.
ballerina run secured_service_with_basic_auth.bal --b7a.config.file=sample-users.toml --b7a.home=<ballerina_home_path>
[ballerina/http] started HTTPS/WSS listener 0.0.0.0:9090# Since the resource configuration has overridden the required scopes to denote
# that `scope2` is required to invoke `sayHello` resource, the invocation will
# fail during authorization.
curl -k -u alice:password1 https://localhost:9090/hello/sayHello
Authorization failure# Since `bob` has `scope2`, the invocation will succeed.
curl -k -u bob:password2 https://localhost:9090/hello/sayHello
Hello, World!!!

Secured Service with Basic Auth

A service can be secured using basic authentication and optionally, by enforcing authorization. The auth provider reads the username and password from a file which has a toml format. This stores usernames, passwords for authentication, and scopes for authorization. Ballerina uses the concept of scopes for authorization. A resource declared in a service can be bound to one/more scope(s). In the config auth provider, scopes are mapped to users. In the authorization phase, the scopes of the resource are compared against the scopes mapped to the user for at least one match between the two sets. The following code block shows the contents of the file sample-users.toml, which has the required format of usernames, passwords and scopes, including their mapping.

  [b7a.users]

  [b7a.users.alice]
  password="password1"
  scopes="scope1"

  [b7a.users.bob]
  password="password2"
  scopes="scope2,scope3"

There are two users defined - Alice and Bob. Each user has a password and assigned scopes.

import ballerina/auth;
import ballerina/config;
import ballerina/http;
import ballerina/log;
auth:InboundBasicAuthProvider basicAuthProvider = new;
http:BasicAuthHandler basicAuthHandler = new (basicAuthProvider);

Creates a Basic Auth header handler with the relevant configurations.

listener http:Listener ep = new (9090, config = {
    auth: {
        authHandlers: [basicAuthHandler]
    },

The endpoint used here is the http:Listener, which by default tries to authenticate and authorize each request. The Basic Authentication handler is set to this endpoint using the authHandlers attribute. It is optional to override the authentication and authorization at the service level and/or resource level.

    secureSocket: {
        keyStore: {
            path: config:getAsString("b7a.home") +
                  "/bre/security/ballerinaKeystore.p12",
            password: "ballerina"
        }
    }
});

The secure hello world sample uses HTTPS.

@http:ServiceConfig {
    basePath: "/hello",
    auth: {
        scopes: ["scope1"]
    }
}
service echo on ep {

The Auth configuration comprises of two parts - authentication & authorization. Authentication can be disabled by setting the enabled: false annotation attribute. Authorization is based on scopes. A scope maps to one or more groups. For a user to access a resource, the user should be in the same groups as the scope. To specify one or more scopes of a resource, the scopes annotation attribute can be used.

    @http:ResourceConfig {
        methods: ["GET"],
        path: "/sayHello",
        auth: {
            scopes: ["scope2"]
        }
    }
    resource function hello(http:Caller caller, http:Request req) {
        error? result = caller->respond("Hello, World!!!");
        if (result is error) {
            log:printError("Error in responding to caller", result);
        }
    }
}

The authentication and authorization settings can be overridden at the resource level. The hello resource would inherit the enabled: true flag from the service level, which is set automatically. The service level scope (i.e., scope1) will be overridden by the scope defined in the resource level (i.e., scope2).

# At the command line, navigate to the directory that contains the `.bal` file.
# Ensure that the `sample-users.toml` file is populated correctly with the user
# information. If required, user passwords can be encrypted using the
# `ballerina encrypt` configuration encryption command.
echo '["b7a.users"]
["b7a.users.alice"]
password="password1"
scopes="scope1"
["b7a.users.bob"]
password="password2"
scopes="scope2,scope3"' > sample-users.toml
# To run the service, execute the below command by specifying the configuration
# file name and passing Ballerina home path as a system property.
ballerina run secured_service_with_basic_auth.bal --b7a.config.file=sample-users.toml --b7a.home=<ballerina_home_path>
[ballerina/http] started HTTPS/WSS listener 0.0.0.0:9090
# Since the resource configuration has overridden the required scopes to denote
# that `scope2` is required to invoke `sayHello` resource, the invocation will
# fail during authorization.
curl -k -u alice:password1 https://localhost:9090/hello/sayHello
Authorization failure
# Since `bob` has `scope2`, the invocation will succeed.
curl -k -u bob:password2 https://localhost:9090/hello/sayHello
Hello, World!!!