diff --git a/examples/secured-client-with-basic-auth/secured_client_with_basic_auth.bal b/examples/secured-client-with-basic-auth/secured_client_with_basic_auth.bal index 8b0e88eaaa24..6d9694044904 100644 --- a/examples/secured-client-with-basic-auth/secured_client_with_basic_auth.bal +++ b/examples/secured-client-with-basic-auth/secured_client_with_basic_auth.bal @@ -1,3 +1,4 @@ +import ballerina/auth; import ballerina/config; import ballerina/http; import ballerina/log; @@ -30,14 +31,14 @@ public function main() { } } -// Create a basic authentication provider with the relevant configurations. -http:AuthProvider basicAuthProvider = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +// Create a Basic authentication handler with the relevant configurations. +auth:ConfigAuthStoreProvider basicAuthProvider = new; +http:BasicAuthnHandler basicAuthnHandler = new(basicAuthProvider); listener http:Listener ep = new(9090, config = { - authProviders: [basicAuthProvider], + auth: { + authnHandlers: [basicAuthnHandler] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -48,8 +49,8 @@ listener http:Listener ep = new(9090, config = { @http:ServiceConfig { basePath: "/hello", - authConfig: { - authentication: { enabled: true } + auth: { + enabled: true } } service echo on ep { diff --git a/examples/secured-client-with-jwt-auth/secured_client_with_jwt_auth.bal b/examples/secured-client-with-jwt-auth/secured_client_with_jwt_auth.bal index f7914a485a76..dd18072de726 100644 --- a/examples/secured-client-with-jwt-auth/secured_client_with_jwt_auth.bal +++ b/examples/secured-client-with-jwt-auth/secured_client_with_jwt_auth.bal @@ -1,3 +1,4 @@ +import ballerina/auth; import ballerina/http; import ballerina/log; import ballerina/runtime; @@ -38,21 +39,23 @@ public function main() { } // Create a JWT authentication provider with the relevant configurations. -http:AuthProvider jwtAuthProvider = { - scheme: http:JWT_AUTH, - config: { - issuer: "ballerina", - audience: ["ballerina.io"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider = new({ + issuer: "ballerina", + audience: ["ballerina.io"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); + +// Create a JWT authentication handler with the created JWT auth provider. +http:JwtAuthnHandler jwtAuthnHandler = new(jwtAuthProvider); listener http:Listener ep = new(9090, config = { - authProviders: [jwtAuthProvider], + auth: { + authnHandlers: [jwtAuthnHandler] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -63,8 +66,8 @@ listener http:Listener ep = new(9090, config = { @http:ServiceConfig { basePath: "/hello", - authConfig: { - authentication: { enabled: true } + auth: { + enabled: true } } service echo on ep { diff --git a/examples/secured-service-with-basic-auth/secured_service_with_basic_auth.bal b/examples/secured-service-with-basic-auth/secured_service_with_basic_auth.bal index d39386da5fa6..f8ba9b8f6ba6 100644 --- a/examples/secured-service-with-basic-auth/secured_service_with_basic_auth.bal +++ b/examples/secured-service-with-basic-auth/secured_service_with_basic_auth.bal @@ -1,18 +1,19 @@ +import ballerina/auth; import ballerina/http; import ballerina/log; -http:AuthProvider basicAuthProvider = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +// Create a Basic authentication handler with the relevant configurations. +auth:ConfigAuthStoreProvider basicAuthProvider = new; +http:BasicAuthnHandler basicAuthnHandler = new(basicAuthProvider); -// The endpoint used here is `http:Listener`, which by default tries to -// authenticate and authorize each request. The developer has the option to -// override the authentication and authorization at the service level and -// resource level. +// The endpoint used here is the `http:Listener`, which by default tries to +// authenticate and authorize each request. It is optional to override the +// authentication and authorization at the service level and/or resource level. listener http:Listener ep = new(9090, config = { - authProviders: [basicAuthProvider], - // The secure hello world sample uses https. + auth: { + authnHandlers: [basicAuthnHandler] + }, + // The secure hello world sample uses HTTPS. secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -23,15 +24,14 @@ listener http:Listener ep = new(9090, config = { @http:ServiceConfig { basePath: "/hello", - authConfig: { - authentication: { enabled: true }, + auth: { scopes: ["scope1"] } } -// Auth configuration comprises of two parts - authentication & authorization. -// Authentication can be enabled by setting the `authentication:{enabled:true}` -// annotation attribute. -// Authorization is based on scopes, where a scope maps to one or more groups. +// 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 @@ -41,15 +41,16 @@ service echo on ep { @http:ResourceConfig { methods: ["GET"], path: "/sayHello", - authConfig: { + auth: { scopes: ["scope2"] } } - // The authentication and authorization settings can be overridden at + // The authentication and authorization settings can be overridden at the // resource level. - // The hello resource would inherit the `authentication:{enabled:true}` - // flag from the service level, and override the scope defined in the - // service level (i.e., scope1) with scope2. + // 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). resource function hello(http:Caller caller, http:Request req) { error? result = caller->respond("Hello, World!!!"); if (result is error) { diff --git a/examples/secured-service-with-jwt/secured_service_with_jwt.bal b/examples/secured-service-with-jwt/secured_service_with_jwt.bal index 473fa409b070..c94775064e5c 100644 --- a/examples/secured-service-with-jwt/secured_service_with_jwt.bal +++ b/examples/secured-service-with-jwt/secured_service_with_jwt.bal @@ -1,27 +1,30 @@ +import ballerina/auth; import ballerina/http; import ballerina/log; -// Create a JWT authentication provider with the relevant configuration -// parameters. -http:AuthProvider jwtAuthProvider = { - scheme: http:JWT_AUTH, - config: { - issuer:"ballerina", - audience: ["ballerina.io"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +// Create a JWT authentication provider with the relevant configurations. +auth:JWTAuthProvider jwtAuthProvider = new({ + issuer: "ballerina", + audience: ["ballerina.io"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; -// The endpoint used here is `http:Listener`. The JWT authentication -// provider is set to this endpoint using the `authProviders` attribute. The -// developer has the option to override the authentication and authorization -// at the service and resource levels. +}); + +// Create a JWT authentication handler with the created JWT auth provider. +http:JwtAuthnHandler jwtAuthnHandler = new(jwtAuthProvider); + +// The endpoint used here is the `http:Listener`. The JWT authentication +// handler is set to this endpoint using the `authnHandlers` attribute. +// It is optional to override the authentication and authorization at the +// service and resource levels. listener http:Listener ep = new(9090, config = { - authProviders:[jwtAuthProvider], - // The secure hello world sample uses https. + auth: { + authnHandlers: [jwtAuthnHandler] + }, + // The secure hello world sample uses HTTPS. secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -31,15 +34,11 @@ listener http:Listener ep = new(9090, config = { }); @http:ServiceConfig { - basePath: "/hello", - authConfig: { - authentication: { enabled: true } - } + basePath: "/hello" } -// Auth configuration comprises of two parts - authentication & authorization. -// Authentication can be enabled by setting the `authentication:{enabled:true}` -// flag. -// Authorization is based on scopes, where a scope maps to one or more groups. +// The Auth configuration comprises of two parts - authentication & authorization. +// Authentication can be disabled by setting the `enabled: false` flag. +// 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 scope of a resource, the annotation attribute @@ -48,14 +47,15 @@ service echo on ep { @http:ResourceConfig { methods: ["GET"], path: "/sayHello", - authConfig: { + auth: { scopes: ["hello"] } } // The authentication and authorization settings can be overridden at - // resource level. - // The hello resource would inherit the `authentication:{enabled:true}` flag - // from the service level, and define `hello` as the scope for the resource. + // the resource level. + // The hello resource would inherit the `enabled: true` flag from the + // service level, which is set automatically. + // The scope of the resource is defined as "hello". resource function hello(http:Caller caller, http:Request req) { error? result = caller->respond("Hello, World!!!"); if (result is error) { diff --git a/language-server/modules/langserver-core/src/test/resources/command/source/testgen/module2/services.bal b/language-server/modules/langserver-core/src/test/resources/command/source/testgen/module2/services.bal index 9f92d6b7c5e3..dec1205bb269 100644 --- a/language-server/modules/langserver-core/src/test/resources/command/source/testgen/module2/services.bal +++ b/language-server/modules/langserver-core/src/test/resources/command/source/testgen/module2/services.bal @@ -1,6 +1,6 @@ +import ballerina/auth; import ballerina/http; import ballerina/io; -import ballerina/websub; service httpService on new http:Listener(9090) { resource function sayHello(http:Caller caller, http:Request request) { @@ -32,32 +32,32 @@ service wssService on securedListener2 { } } -http:AuthProvider basicAuthProvider = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +auth:ConfigAuthStoreProvider basicAuthProvider1 = new; +auth:ConfigAuthStoreProvider basicAuthProvider2 = new; -http:AuthProvider basicAuthProvider2 = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +http:BasicAuthnHandler basicAuthnHandler1 = new(basicAuthProvider1); +http:BasicAuthnHandler basicAuthnHandler2 = new(basicAuthProvider2); listener http:Listener securedListener = new(9090, config = { - authProviders: [basicAuthProvider], - secureSocket: { - keyStore: { - path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", - password: "ballerina" + auth: { + authnHandlers: [basicAuthnHandler1] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" + } } - } -}); + }); listener http:WebSocketListener securedListener2 = new(9090, config = { - authProviders: [basicAuthProvider], - secureSocket: { - keyStore: { - path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", - password: "ballerina" + auth: { + authnHandlers: [basicAuthnHandler2] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" + } } - } -}); + }); diff --git a/language-server/modules/langserver-core/src/test/resources/command/testGenerationForServicesNegative.json b/language-server/modules/langserver-core/src/test/resources/command/testGenerationForServicesNegative.json index 544e5801c09f..ef6282b38404 100644 --- a/language-server/modules/langserver-core/src/test/resources/command/testGenerationForServicesNegative.json +++ b/language-server/modules/langserver-core/src/test/resources/command/testGenerationForServicesNegative.json @@ -2,8 +2,8 @@ "cases": [ { "arguments": { - "node.line": 34, - "node.column": 20 + "node.line": 35, + "node.column": 30 }, "expected": { "imports": [], diff --git a/language-server/modules/langserver-core/src/test/resources/completion/annotation/serviceAnnotation3.json b/language-server/modules/langserver-core/src/test/resources/completion/annotation/serviceAnnotation3.json index b9cf4be0998c..b826d31d614e 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/annotation/serviceAnnotation3.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/annotation/serviceAnnotation3.json @@ -62,11 +62,11 @@ "insertTextFormat": "Snippet" }, { - "label": "authConfig", + "label": "auth", "kind": "Field", "detail": "Field", "sortText": "120", - "insertText": "authConfig: ${1:{}} // Values allowed: ballerina/http:ListenerAuthConfig|()", + "insertText": "auth: {\n\t${1}\n}", "insertTextFormat": "Snippet" }, { @@ -74,8 +74,8 @@ "kind": "Property", "detail": "none", "sortText": "110", - "insertText": "endpoints: [],\nhost: \"\",\nbasePath: \"\",\ncompression: {},\nchunking: \"AUTO\", // Values allowed: AUTO|ALWAYS|NEVER,\ncors: {},\nversioning: {},\nauthConfig: {} // Values allowed: ballerina/http:ListenerAuthConfig|()", + "insertText": "endpoints: [],\nhost: \"\",\nbasePath: \"\",\ncompression: {},\nchunking: \"AUTO\", // Values allowed: AUTO|ALWAYS|NEVER,\ncors: {},\nversioning: {},\nauth: {}", "insertTextFormat": "Snippet" } ] -} \ No newline at end of file +} diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions4.json b/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions4.json index 243934eeafe0..3bf7b904c742 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions4.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions4.json @@ -6,14 +6,14 @@ "source": "function/source/matchStatementSuggestions4.bal", "items": [ { - "label":"extractBasicAuthHeaderValue(req)", + "label":"extractAuthorizationHeaderValue(req)", "kind":"Function", "detail":"Snippet", "documentation":{ - "left":"Extracts the basic authentication header value from the request.\n" + "left":"Extracts the Authorization header value from the request.\n" }, "sortText":"120", - "insertText":"extractBasicAuthHeaderValue(req) {\n${1:value} \u003d\u003e {${2}}\n}", + "insertText":"extractAuthorizationHeaderValue(req) {\n${1:value} \u003d\u003e {${2}}\n}", "insertTextFormat":"Snippet" }, { diff --git a/language-server/modules/langserver-core/src/test/resources/completion/packageimport/packageImport.json b/language-server/modules/langserver-core/src/test/resources/completion/packageimport/packageImport.json index 8a6d24b87319..2cdb8af998f9 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/packageimport/packageImport.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/packageimport/packageImport.json @@ -6,17 +6,17 @@ "source": "packageimport/source/packageImport.bal", "items": [ { - "label": "extractBasicAuthHeaderValue(http:Request req)(string?)", + "label": "extractAuthorizationHeaderValue(http:Request req)(string)", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts the basic authentication header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring?" + "value": "**Package:** _ballerina/http_ \n \nExtracts the Authorization header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring" } }, "sortText": "121", - "insertText": "extractBasicAuthHeaderValue(${1:req})", + "insertText": "extractAuthorizationHeaderValue(${1:req})", "insertTextFormat": "Snippet" }, { @@ -170,25 +170,14 @@ "insertTextFormat": "Snippet" }, { - "label": "ListenerAuthConfig", + "label": "ServiceResourceAuth", "kind": "Class", "detail": "Record", "documentation": { "left": "Configures the authentication scheme for a service or a resource.\n" }, "sortText": "221", - "insertText": "ListenerAuthConfig", - "insertTextFormat": "Snippet" - }, - { - "label": "Authentication", - "kind": "Class", - "detail": "Record", - "documentation": { - "left": "Can be used for enabling/disabling authentication in an HTTP service.\n" - }, - "sortText": "221", - "insertText": "Authentication", + "insertText": "ServiceResourceAuth", "insertTextFormat": "Snippet" }, { @@ -251,7 +240,7 @@ "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides configurations for controlling the endpoint\u0027s behaviour in response to HTTP redirect related responses.\n" + "left": "Provides configurations for controlling the endpoint's behaviour in response to HTTP redirect related responses.\n" }, "sortText": "221", "insertText": "FollowRedirects", @@ -269,14 +258,14 @@ "insertTextFormat": "Snippet" }, { - "label": "AuthConfig", + "label": "OutboundAuthConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "The `AuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" + "left": "The `OutboundAuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" }, "sortText": "221", - "insertText": "AuthConfig", + "insertText": "OutboundAuthConfig", "insertTextFormat": "Snippet" }, { @@ -621,36 +610,36 @@ "insertTextFormat": "Snippet" }, { - "label": "ServiceSecureSocket", + "label": "ListenerAuth", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configures the SSL/TLS options to be used for HTTP service.\n" + "left": "Authentication configurations for the listener.\n" }, "sortText": "221", - "insertText": "ServiceSecureSocket", + "insertText": "ListenerAuth", "insertTextFormat": "Snippet" }, { - "label": "AuthCacheConfig", + "label": "ServiceSecureSocket", "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" + "left": "Configures the SSL/TLS options to be used for HTTP service.\n" }, "sortText": "221", - "insertText": "AuthCacheConfig", + "insertText": "ServiceSecureSocket", "insertTextFormat": "Snippet" }, { - "label": "AuthProvider", + "label": "AuthCacheConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configuration for authentication providers.\n" + "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" }, "sortText": "221", - "insertText": "AuthProvider", + "insertText": "AuthCacheConfig", "insertTextFormat": "Snippet" }, { @@ -664,17 +653,6 @@ "insertText": "WebSocketClientEndpointConfig", "insertTextFormat": "Snippet" }, - { - "label": "AuthHandlerRegistry", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of the Http Auth Handler Registry.\n" - }, - "sortText": "221", - "insertText": "AuthHandlerRegistry", - "insertTextFormat": "Snippet" - }, { "label": "AuthnFilter", "kind": "Class", @@ -687,25 +665,14 @@ "insertTextFormat": "Snippet" }, { - "label": "HttpAuthnHandler", + "label": "AuthnHandler", "kind": "Class", "detail": "Object", "documentation": { - "left": "Representation of Authentication handler for HTTP traffic.\n" + "left": "Representation of Authentication handler for HTTP traffic." }, "sortText": "221", - "insertText": "HttpAuthnHandler", - "insertTextFormat": "Snippet" - }, - { - "label": "AuthnHandlerChain", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of Authentication handler chain\n" - }, - "sortText": "221", - "insertText": "AuthnHandlerChain", + "insertText": "AuthnHandler", "insertTextFormat": "Snippet" }, { @@ -720,36 +687,36 @@ "insertTextFormat": "Snippet" }, { - "label": "HttpAuthzHandler", + "label": "AuthzHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of Authorization Handler for HTTP\n" }, "sortText": "221", - "insertText": "HttpAuthzHandler", + "insertText": "AuthzHandler", "insertTextFormat": "Snippet" }, { - "label": "HttpBasicAuthnHandler", + "label": "BasicAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Defines Basic Auth handler for HTTP traffic.\n" }, "sortText": "221", - "insertText": "HttpBasicAuthnHandler", + "insertText": "BasicAuthnHandler", "insertTextFormat": "Snippet" }, { - "label": "HttpJwtAuthnHandler", + "label": "JwtAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of JWT Auth handler for HTTP traffic\n" }, "sortText": "221", - "insertText": "HttpJwtAuthnHandler", + "insertText": "JwtAuthnHandler", "insertTextFormat": "Snippet" }, { @@ -778,6 +745,9 @@ "label": "HttpCache", "kind": "Class", "detail": "Object", + "documentation": { + "left": "Implements a cache for storing HTTP responses. This cache complies with the caching policy set when configuring\nHTTP caching in the HTTP client endpoint.\n" + }, "sortText": "221", "insertText": "HttpCache", "insertTextFormat": "Snippet" @@ -787,7 +757,7 @@ "kind": "Class", "detail": "Object", "documentation": { - "left": "Represents a \u0027future\u0027 that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." + "left": "Represents a 'future' that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." }, "sortText": "221", "insertText": "HttpFuture", @@ -1068,17 +1038,6 @@ "insertText": "OutboundAuthScheme", "insertTextFormat": "Snippet" }, - { - "label": "AuthStoreProvider", - "kind": "Enum", - "detail": "Union", - "documentation": { - "left": "Authentication storage providers for BasicAuth scheme." - }, - "sortText": "221", - "insertText": "AuthStoreProvider", - "insertTextFormat": "Snippet" - }, { "label": "CachingPolicy", "kind": "Enum", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion5.json b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion5.json index 5554007ee109..0bf36b7c7884 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion5.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion5.json @@ -6,17 +6,17 @@ "source": "service/source/serviceBodyCompletion5.bal", "items": [ { - "label": "extractBasicAuthHeaderValue(http:Request req)(string?)", + "label": "extractAuthorizationHeaderValue(http:Request req)(string)", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts the basic authentication header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring?" + "value": "**Package:** _ballerina/http_ \n \nExtracts the Authorization header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring" } }, "sortText": "121", - "insertText": "extractBasicAuthHeaderValue(${1:req})", + "insertText": "extractAuthorizationHeaderValue(${1:req})", "insertTextFormat": "Snippet" }, { @@ -170,25 +170,14 @@ "insertTextFormat": "Snippet" }, { - "label": "ListenerAuthConfig", + "label": "ServiceResourceAuth", "kind": "Class", "detail": "Record", "documentation": { "left": "Configures the authentication scheme for a service or a resource.\n" }, "sortText": "221", - "insertText": "ListenerAuthConfig", - "insertTextFormat": "Snippet" - }, - { - "label": "Authentication", - "kind": "Class", - "detail": "Record", - "documentation": { - "left": "Can be used for enabling/disabling authentication in an HTTP service.\n" - }, - "sortText": "221", - "insertText": "Authentication", + "insertText": "ServiceResourceAuth", "insertTextFormat": "Snippet" }, { @@ -251,7 +240,7 @@ "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides configurations for controlling the endpoint\u0027s behaviour in response to HTTP redirect related responses.\n" + "left": "Provides configurations for controlling the endpoint's behaviour in response to HTTP redirect related responses.\n" }, "sortText": "221", "insertText": "FollowRedirects", @@ -269,14 +258,14 @@ "insertTextFormat": "Snippet" }, { - "label": "AuthConfig", + "label": "OutboundAuthConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "The `AuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" + "left": "The `OutboundAuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" }, "sortText": "221", - "insertText": "AuthConfig", + "insertText": "OutboundAuthConfig", "insertTextFormat": "Snippet" }, { @@ -621,36 +610,36 @@ "insertTextFormat": "Snippet" }, { - "label": "ServiceSecureSocket", + "label": "ListenerAuth", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configures the SSL/TLS options to be used for HTTP service.\n" + "left": "Authentication configurations for the listener.\n" }, "sortText": "221", - "insertText": "ServiceSecureSocket", + "insertText": "ListenerAuth", "insertTextFormat": "Snippet" }, { - "label": "AuthCacheConfig", + "label": "ServiceSecureSocket", "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" + "left": "Configures the SSL/TLS options to be used for HTTP service.\n" }, "sortText": "221", - "insertText": "AuthCacheConfig", + "insertText": "ServiceSecureSocket", "insertTextFormat": "Snippet" }, { - "label": "AuthProvider", + "label": "AuthCacheConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configuration for authentication providers.\n" + "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" }, "sortText": "221", - "insertText": "AuthProvider", + "insertText": "AuthCacheConfig", "insertTextFormat": "Snippet" }, { @@ -664,17 +653,6 @@ "insertText": "WebSocketClientEndpointConfig", "insertTextFormat": "Snippet" }, - { - "label": "AuthHandlerRegistry", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of the Http Auth Handler Registry.\n" - }, - "sortText": "221", - "insertText": "AuthHandlerRegistry", - "insertTextFormat": "Snippet" - }, { "label": "AuthnFilter", "kind": "Class", @@ -687,25 +665,14 @@ "insertTextFormat": "Snippet" }, { - "label": "HttpAuthnHandler", + "label": "AuthnHandler", "kind": "Class", "detail": "Object", "documentation": { - "left": "Representation of Authentication handler for HTTP traffic.\n" + "left": "Representation of Authentication handler for HTTP traffic." }, "sortText": "221", - "insertText": "HttpAuthnHandler", - "insertTextFormat": "Snippet" - }, - { - "label": "AuthnHandlerChain", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of Authentication handler chain\n" - }, - "sortText": "221", - "insertText": "AuthnHandlerChain", + "insertText": "AuthnHandler", "insertTextFormat": "Snippet" }, { @@ -720,36 +687,36 @@ "insertTextFormat": "Snippet" }, { - "label": "HttpAuthzHandler", + "label": "AuthzHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of Authorization Handler for HTTP\n" }, "sortText": "221", - "insertText": "HttpAuthzHandler", + "insertText": "AuthzHandler", "insertTextFormat": "Snippet" }, { - "label": "HttpBasicAuthnHandler", + "label": "BasicAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Defines Basic Auth handler for HTTP traffic.\n" }, "sortText": "221", - "insertText": "HttpBasicAuthnHandler", + "insertText": "BasicAuthnHandler", "insertTextFormat": "Snippet" }, { - "label": "HttpJwtAuthnHandler", + "label": "JwtAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of JWT Auth handler for HTTP traffic\n" }, "sortText": "221", - "insertText": "HttpJwtAuthnHandler", + "insertText": "JwtAuthnHandler", "insertTextFormat": "Snippet" }, { @@ -778,6 +745,9 @@ "label": "HttpCache", "kind": "Class", "detail": "Object", + "documentation": { + "left": "Implements a cache for storing HTTP responses. This cache complies with the caching policy set when configuring\nHTTP caching in the HTTP client endpoint.\n" + }, "sortText": "221", "insertText": "HttpCache", "insertTextFormat": "Snippet" @@ -787,7 +757,7 @@ "kind": "Class", "detail": "Object", "documentation": { - "left": "Represents a \u0027future\u0027 that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." + "left": "Represents a 'future' that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." }, "sortText": "221", "insertText": "HttpFuture", @@ -1068,17 +1038,6 @@ "insertText": "OutboundAuthScheme", "insertTextFormat": "Snippet" }, - { - "label": "AuthStoreProvider", - "kind": "Enum", - "detail": "Union", - "documentation": { - "left": "Authentication storage providers for BasicAuth scheme." - }, - "sortText": "221", - "insertText": "AuthStoreProvider", - "insertTextFormat": "Snippet" - }, { "label": "CachingPolicy", "kind": "Enum", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceEndpointBind4.json b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceEndpointBind4.json index ef3fd76e9d18..0e6f622b84e2 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceEndpointBind4.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceEndpointBind4.json @@ -6,16 +6,16 @@ "source": "service/source/serviceEndpointBind4.bal", "items": [ { - "label": "extractBasicAuthHeaderValue(http:Request req)(string?)", + "label": "extractAuthorizationHeaderValue(http:Request req)(string)", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts the basic authentication header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring?" + "value": "**Package:** _ballerina/http_ \n \nExtracts the Authorization header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring" } }, - "insertText": "extractBasicAuthHeaderValue(${1:req})", + "insertText": "extractAuthorizationHeaderValue(${1:req})", "insertTextFormat": "Snippet" }, { @@ -157,23 +157,13 @@ "insertTextFormat": "Snippet" }, { - "label": "ListenerAuthConfig", + "label": "ServiceResourceAuth", "kind": "Class", "detail": "Record", "documentation": { "left": "Configures the authentication scheme for a service or a resource.\n" }, - "insertText": "ListenerAuthConfig", - "insertTextFormat": "Snippet" - }, - { - "label": "Authentication", - "kind": "Class", - "detail": "Record", - "documentation": { - "left": "Can be used for enabling/disabling authentication in an HTTP service.\n" - }, - "insertText": "Authentication", + "insertText": "ServiceResourceAuth", "insertTextFormat": "Snippet" }, { @@ -231,7 +221,7 @@ "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides configurations for controlling the endpoint\u0027s behaviour in response to HTTP redirect related responses.\n" + "left": "Provides configurations for controlling the endpoint's behaviour in response to HTTP redirect related responses.\n" }, "insertText": "FollowRedirects", "insertTextFormat": "Snippet" @@ -247,13 +237,13 @@ "insertTextFormat": "Snippet" }, { - "label": "AuthConfig", + "label": "OutboundAuthConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "The `AuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" + "left": "The `OutboundAuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" }, - "insertText": "AuthConfig", + "insertText": "OutboundAuthConfig", "insertTextFormat": "Snippet" }, { @@ -567,33 +557,33 @@ "insertTextFormat": "Snippet" }, { - "label": "ServiceSecureSocket", + "label": "ListenerAuth", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configures the SSL/TLS options to be used for HTTP service.\n" + "left": "Authentication configurations for the listener.\n" }, - "insertText": "ServiceSecureSocket", + "insertText": "ListenerAuth", "insertTextFormat": "Snippet" }, { - "label": "AuthCacheConfig", + "label": "ServiceSecureSocket", "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" + "left": "Configures the SSL/TLS options to be used for HTTP service.\n" }, - "insertText": "AuthCacheConfig", + "insertText": "ServiceSecureSocket", "insertTextFormat": "Snippet" }, { - "label": "AuthProvider", + "label": "AuthCacheConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configuration for authentication providers.\n" + "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" }, - "insertText": "AuthProvider", + "insertText": "AuthCacheConfig", "insertTextFormat": "Snippet" }, { @@ -606,16 +596,6 @@ "insertText": "WebSocketClientEndpointConfig", "insertTextFormat": "Snippet" }, - { - "label": "AuthHandlerRegistry", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of the Http Auth Handler Registry.\n" - }, - "insertText": "AuthHandlerRegistry", - "insertTextFormat": "Snippet" - }, { "label": "AuthnFilter", "kind": "Class", @@ -627,23 +607,13 @@ "insertTextFormat": "Snippet" }, { - "label": "HttpAuthnHandler", + "label": "AuthnHandler", "kind": "Class", "detail": "Object", "documentation": { - "left": "Representation of Authentication handler for HTTP traffic.\n" + "left": "Representation of Authentication handler for HTTP traffic." }, - "insertText": "HttpAuthnHandler", - "insertTextFormat": "Snippet" - }, - { - "label": "AuthnHandlerChain", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of Authentication handler chain\n" - }, - "insertText": "AuthnHandlerChain", + "insertText": "AuthnHandler", "insertTextFormat": "Snippet" }, { @@ -657,33 +627,33 @@ "insertTextFormat": "Snippet" }, { - "label": "HttpAuthzHandler", + "label": "AuthzHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of Authorization Handler for HTTP\n" }, - "insertText": "HttpAuthzHandler", + "insertText": "AuthzHandler", "insertTextFormat": "Snippet" }, { - "label": "HttpBasicAuthnHandler", + "label": "BasicAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Defines Basic Auth handler for HTTP traffic.\n" }, - "insertText": "HttpBasicAuthnHandler", + "insertText": "BasicAuthnHandler", "insertTextFormat": "Snippet" }, { - "label": "HttpJwtAuthnHandler", + "label": "JwtAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of JWT Auth handler for HTTP traffic\n" }, - "insertText": "HttpJwtAuthnHandler", + "insertText": "JwtAuthnHandler", "insertTextFormat": "Snippet" }, { @@ -710,6 +680,9 @@ "label": "HttpCache", "kind": "Class", "detail": "Object", + "documentation": { + "left": "Implements a cache for storing HTTP responses. This cache complies with the caching policy set when configuring\nHTTP caching in the HTTP client endpoint.\n" + }, "insertText": "HttpCache", "insertTextFormat": "Snippet" }, @@ -718,7 +691,7 @@ "kind": "Class", "detail": "Object", "documentation": { - "left": "Represents a \u0027future\u0027 that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." + "left": "Represents a 'future' that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." }, "insertText": "HttpFuture", "insertTextFormat": "Snippet" @@ -973,16 +946,6 @@ "insertText": "OutboundAuthScheme", "insertTextFormat": "Snippet" }, - { - "label": "AuthStoreProvider", - "kind": "Enum", - "detail": "Union", - "documentation": { - "left": "Authentication storage providers for BasicAuth scheme." - }, - "insertText": "AuthStoreProvider", - "insertTextFormat": "Snippet" - }, { "label": "CachingPolicy", "kind": "Enum", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/globalVarDefPackageContent.json b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/globalVarDefPackageContent.json index 18f3f46f0e7a..71ab2c1726d5 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/globalVarDefPackageContent.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/globalVarDefPackageContent.json @@ -6,17 +6,17 @@ "source": "toplevel/source/globalVarDefPackageContent.bal", "items": [ { - "label": "extractBasicAuthHeaderValue(http:Request req)(string?)", + "label": "extractAuthorizationHeaderValue(http:Request req)(string)", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts the basic authentication header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring?" + "value": "**Package:** _ballerina/http_ \n \nExtracts the Authorization header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring" } }, "sortText": "121", - "insertText": "extractBasicAuthHeaderValue(${1:req})", + "insertText": "extractAuthorizationHeaderValue(${1:req})", "insertTextFormat": "Snippet" }, { @@ -170,25 +170,14 @@ "insertTextFormat": "Snippet" }, { - "label": "ListenerAuthConfig", + "label": "ServiceResourceAuth", "kind": "Class", "detail": "Record", "documentation": { "left": "Configures the authentication scheme for a service or a resource.\n" }, "sortText": "221", - "insertText": "ListenerAuthConfig", - "insertTextFormat": "Snippet" - }, - { - "label": "Authentication", - "kind": "Class", - "detail": "Record", - "documentation": { - "left": "Can be used for enabling/disabling authentication in an HTTP service.\n" - }, - "sortText": "221", - "insertText": "Authentication", + "insertText": "ServiceResourceAuth", "insertTextFormat": "Snippet" }, { @@ -251,7 +240,7 @@ "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides configurations for controlling the endpoint\u0027s behaviour in response to HTTP redirect related responses.\n" + "left": "Provides configurations for controlling the endpoint's behaviour in response to HTTP redirect related responses.\n" }, "sortText": "221", "insertText": "FollowRedirects", @@ -269,14 +258,14 @@ "insertTextFormat": "Snippet" }, { - "label": "AuthConfig", + "label": "OutboundAuthConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "The `AuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" + "left": "The `OutboundAuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" }, "sortText": "221", - "insertText": "AuthConfig", + "insertText": "OutboundAuthConfig", "insertTextFormat": "Snippet" }, { @@ -621,36 +610,36 @@ "insertTextFormat": "Snippet" }, { - "label": "ServiceSecureSocket", + "label": "ListenerAuth", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configures the SSL/TLS options to be used for HTTP service.\n" + "left": "Authentication configurations for the listener.\n" }, "sortText": "221", - "insertText": "ServiceSecureSocket", + "insertText": "ListenerAuth", "insertTextFormat": "Snippet" }, { - "label": "AuthCacheConfig", + "label": "ServiceSecureSocket", "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" + "left": "Configures the SSL/TLS options to be used for HTTP service.\n" }, "sortText": "221", - "insertText": "AuthCacheConfig", + "insertText": "ServiceSecureSocket", "insertTextFormat": "Snippet" }, { - "label": "AuthProvider", + "label": "AuthCacheConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configuration for authentication providers.\n" + "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" }, "sortText": "221", - "insertText": "AuthProvider", + "insertText": "AuthCacheConfig", "insertTextFormat": "Snippet" }, { @@ -664,17 +653,6 @@ "insertText": "WebSocketClientEndpointConfig", "insertTextFormat": "Snippet" }, - { - "label": "AuthHandlerRegistry", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of the Http Auth Handler Registry.\n" - }, - "sortText": "221", - "insertText": "AuthHandlerRegistry", - "insertTextFormat": "Snippet" - }, { "label": "AuthnFilter", "kind": "Class", @@ -687,25 +665,14 @@ "insertTextFormat": "Snippet" }, { - "label": "HttpAuthnHandler", + "label": "AuthnHandler", "kind": "Class", "detail": "Object", "documentation": { - "left": "Representation of Authentication handler for HTTP traffic.\n" + "left": "Representation of Authentication handler for HTTP traffic." }, "sortText": "221", - "insertText": "HttpAuthnHandler", - "insertTextFormat": "Snippet" - }, - { - "label": "AuthnHandlerChain", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of Authentication handler chain\n" - }, - "sortText": "221", - "insertText": "AuthnHandlerChain", + "insertText": "AuthnHandler", "insertTextFormat": "Snippet" }, { @@ -720,36 +687,36 @@ "insertTextFormat": "Snippet" }, { - "label": "HttpAuthzHandler", + "label": "AuthzHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of Authorization Handler for HTTP\n" }, "sortText": "221", - "insertText": "HttpAuthzHandler", + "insertText": "AuthzHandler", "insertTextFormat": "Snippet" }, { - "label": "HttpBasicAuthnHandler", + "label": "BasicAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Defines Basic Auth handler for HTTP traffic.\n" }, "sortText": "221", - "insertText": "HttpBasicAuthnHandler", + "insertText": "BasicAuthnHandler", "insertTextFormat": "Snippet" }, { - "label": "HttpJwtAuthnHandler", + "label": "JwtAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of JWT Auth handler for HTTP traffic\n" }, "sortText": "221", - "insertText": "HttpJwtAuthnHandler", + "insertText": "JwtAuthnHandler", "insertTextFormat": "Snippet" }, { @@ -778,6 +745,9 @@ "label": "HttpCache", "kind": "Class", "detail": "Object", + "documentation": { + "left": "Implements a cache for storing HTTP responses. This cache complies with the caching policy set when configuring\nHTTP caching in the HTTP client endpoint.\n" + }, "sortText": "221", "insertText": "HttpCache", "insertTextFormat": "Snippet" @@ -787,7 +757,7 @@ "kind": "Class", "detail": "Object", "documentation": { - "left": "Represents a \u0027future\u0027 that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." + "left": "Represents a 'future' that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." }, "sortText": "221", "insertText": "HttpFuture", @@ -1068,17 +1038,6 @@ "insertText": "OutboundAuthScheme", "insertTextFormat": "Snippet" }, - { - "label": "AuthStoreProvider", - "kind": "Enum", - "detail": "Union", - "documentation": { - "left": "Authentication storage providers for BasicAuth scheme." - }, - "sortText": "221", - "insertText": "AuthStoreProvider", - "insertTextFormat": "Snippet" - }, { "label": "CachingPolicy", "kind": "Enum", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/topLevelPackageContentAccess.json b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/topLevelPackageContentAccess.json index e1493a7c43cc..11c4acb8b7f9 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/topLevelPackageContentAccess.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/topLevelPackageContentAccess.json @@ -6,16 +6,16 @@ "source": "toplevel/source/topLevelPackageContentAccess.bal", "items": [ { - "label": "extractBasicAuthHeaderValue(http:Request req)(string?)", + "label": "extractAuthorizationHeaderValue(http:Request req)(string)", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts the basic authentication header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring?" + "value": "**Package:** _ballerina/http_ \n \nExtracts the Authorization header value from the request.\n \n \n--- \n**Parameters** \n- _req_ \n Request instance \n \n \n**Return** \nstring" } }, - "insertText": "extractBasicAuthHeaderValue(${1:req})", + "insertText": "extractAuthorizationHeaderValue(${1:req})", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -352,38 +352,13 @@ ] }, { - "label": "ListenerAuthConfig", + "label": "ServiceResourceAuth", "kind": "Class", "detail": "Record", "documentation": { "left": "Configures the authentication scheme for a service or a resource.\n" }, - "insertText": "ListenerAuthConfig", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, - { - "label": "Authentication", - "kind": "Class", - "detail": "Record", - "documentation": { - "left": "Can be used for enabling/disabling authentication in an HTTP service.\n" - }, - "insertText": "Authentication", + "insertText": "ServiceResourceAuth", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -531,7 +506,7 @@ "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides configurations for controlling the endpoint\u0027s behaviour in response to HTTP redirect related responses.\n" + "left": "Provides configurations for controlling the endpoint's behaviour in response to HTTP redirect related responses.\n" }, "insertText": "FollowRedirects", "insertTextFormat": "Snippet", @@ -577,13 +552,13 @@ ] }, { - "label": "AuthConfig", + "label": "OutboundAuthConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "The `AuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" + "left": "The `OutboundAuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint.\n" }, - "insertText": "AuthConfig", + "insertText": "OutboundAuthConfig", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -1377,13 +1352,13 @@ ] }, { - "label": "ServiceSecureSocket", + "label": "ListenerAuth", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configures the SSL/TLS options to be used for HTTP service.\n" + "left": "Authentication configurations for the listener.\n" }, - "insertText": "ServiceSecureSocket", + "insertText": "ListenerAuth", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -1402,13 +1377,13 @@ ] }, { - "label": "AuthCacheConfig", + "label": "ServiceSecureSocket", "kind": "Class", "detail": "Record", "documentation": { - "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" + "left": "Configures the SSL/TLS options to be used for HTTP service.\n" }, - "insertText": "AuthCacheConfig", + "insertText": "ServiceSecureSocket", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -1427,13 +1402,13 @@ ] }, { - "label": "AuthProvider", + "label": "AuthCacheConfig", "kind": "Class", "detail": "Record", "documentation": { - "left": "Configuration for authentication providers.\n" + "left": "Provides a set of configurations for controlling the authorization caching behaviour of the endpoint.\n" }, - "insertText": "AuthProvider", + "insertText": "AuthCacheConfig", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -1476,31 +1451,6 @@ } ] }, - { - "label": "AuthHandlerRegistry", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of the Http Auth Handler Registry.\n" - }, - "insertText": "AuthHandlerRegistry", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, { "label": "AuthnFilter", "kind": "Class", @@ -1527,38 +1477,13 @@ ] }, { - "label": "HttpAuthnHandler", + "label": "AuthnHandler", "kind": "Class", "detail": "Object", "documentation": { - "left": "Representation of Authentication handler for HTTP traffic.\n" + "left": "Representation of Authentication handler for HTTP traffic." }, - "insertText": "HttpAuthnHandler", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, - { - "label": "AuthnHandlerChain", - "kind": "Class", - "detail": "Object", - "documentation": { - "left": "Representation of Authentication handler chain\n" - }, - "insertText": "AuthnHandlerChain", + "insertText": "AuthnHandler", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -1602,13 +1527,13 @@ ] }, { - "label": "HttpAuthzHandler", + "label": "AuthzHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of Authorization Handler for HTTP\n" }, - "insertText": "HttpAuthzHandler", + "insertText": "AuthzHandler", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -1627,13 +1552,13 @@ ] }, { - "label": "HttpBasicAuthnHandler", + "label": "BasicAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Defines Basic Auth handler for HTTP traffic.\n" }, - "insertText": "HttpBasicAuthnHandler", + "insertText": "BasicAuthnHandler", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -1652,13 +1577,13 @@ ] }, { - "label": "HttpJwtAuthnHandler", + "label": "JwtAuthnHandler", "kind": "Class", "detail": "Object", "documentation": { "left": "Representation of JWT Auth handler for HTTP traffic\n" }, - "insertText": "HttpJwtAuthnHandler", + "insertText": "JwtAuthnHandler", "insertTextFormat": "Snippet", "additionalTextEdits": [ { @@ -1730,6 +1655,9 @@ "label": "HttpCache", "kind": "Class", "detail": "Object", + "documentation": { + "left": "Implements a cache for storing HTTP responses. This cache complies with the caching policy set when configuring\nHTTP caching in the HTTP client endpoint.\n" + }, "insertText": "HttpCache", "insertTextFormat": "Snippet", "additionalTextEdits": [ @@ -1753,7 +1681,7 @@ "kind": "Class", "detail": "Object", "documentation": { - "left": "Represents a \u0027future\u0027 that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." + "left": "Represents a 'future' that returns as a result of an asynchronous HTTP request submission.\nThis can be used as a reference to fetch the results of the submission." }, "insertText": "HttpFuture", "insertTextFormat": "Snippet", @@ -2098,31 +2026,6 @@ } ] }, - { - "label": "AuthStoreProvider", - "kind": "Enum", - "detail": "Union", - "documentation": { - "left": "Authentication storage providers for BasicAuth scheme." - }, - "insertText": "AuthStoreProvider", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, { "label": "CachingPolicy", "kind": "Enum", diff --git a/language-server/modules/langserver-core/src/test/resources/definition/expected/expression/defExpressionConnectorInit.json b/language-server/modules/langserver-core/src/test/resources/definition/expected/expression/defExpressionConnectorInit.json index 15386f51c572..1c1885f0c9a7 100644 --- a/language-server/modules/langserver-core/src/test/resources/definition/expected/expression/defExpressionConnectorInit.json +++ b/language-server/modules/langserver-core/src/test/resources/definition/expected/expression/defExpressionConnectorInit.json @@ -3,7 +3,7 @@ "file": "defFl17.bal" }, "position": { - "line": 17, + "line": 15, "character": 43 }, "result": [ @@ -11,11 +11,11 @@ "uri": "defFl17.bal", "range": { "start": { - "line": 2, + "line": 3, "character": 4 }, "end": { - "line": 2, + "line": 3, "character": 8 } } diff --git a/language-server/modules/langserver-core/src/test/resources/definition/expected/expression/defExpressionNamedArgs.json b/language-server/modules/langserver-core/src/test/resources/definition/expected/expression/defExpressionNamedArgs.json index 39dc36101acc..183efa75e821 100644 --- a/language-server/modules/langserver-core/src/test/resources/definition/expected/expression/defExpressionNamedArgs.json +++ b/language-server/modules/langserver-core/src/test/resources/definition/expected/expression/defExpressionNamedArgs.json @@ -4,19 +4,19 @@ }, "position": { "line": 17, - "character": 83 + "character": 30 }, "result": [ { "uri": "defFl17.bal", "range": { "start": { - "line": 4, - "character": 18 + "line": 6, + "character": 23 }, "end": { - "line": 4, - "character": 35 + "line": 6, + "character": 40 } } } diff --git a/language-server/modules/langserver-core/src/test/resources/definition/sources/defFl17.bal b/language-server/modules/langserver-core/src/test/resources/definition/sources/defFl17.bal index 44be82a3c0e8..3d0cbd218db9 100644 --- a/language-server/modules/langserver-core/src/test/resources/definition/sources/defFl17.bal +++ b/language-server/modules/langserver-core/src/test/resources/definition/sources/defFl17.bal @@ -1,12 +1,10 @@ +import ballerina/auth; import ballerina/http; int port = 9090; -http:AuthProvider basicAuthProvider = { - id: "", - scheme: "BASIC_AUTH", - authStoreProvider: "CONFIG_AUTH_STORE" -}; +auth:ConfigAuthStoreProvider basicAuthProvider = new; +http:BasicAuthnHandler basicAuthnHandler = new(basicAuthProvider); http:ServiceSecureSocket secureSocket = { keyStore: { @@ -15,6 +13,9 @@ http:ServiceSecureSocket secureSocket = { } }; -listener http:Listener apiListener = new(port, config = { authProviders: [basicAuthProvider], - secureSocket: secureSocket }); - +listener http:Listener apiListener = new(port, config = { + auth: { + authnHandlers: [basicAuthnHandler] + }, + secureSocket: secureSocket +}); diff --git a/stdlib/auth/src/main/ballerina/auth/Module.md b/stdlib/auth/src/main/ballerina/auth/Module.md index 924afabe7ad3..1104e3b2ebc5 100644 --- a/stdlib/auth/src/main/ballerina/auth/Module.md +++ b/stdlib/auth/src/main/ballerina/auth/Module.md @@ -1,25 +1,24 @@ ## Module Overview -This module provides a set of default authentication store providers that can be extended to create new authentication store providers. +This module provides a set of default authentication provider configurations that can be extended to create new authentication providers. -### Authentication Store Provider +### Authentication Provider -An authentication store provider defines an authentication scheme that could be used to protect endpoints. The `auth:AuthStoreProvider` type acts as the interface for all the authentication providers. Any type of implementation, such as LDAP, JDBC, and file based, should be object-wise similar. +An authentication provider defines an authentication scheme that could be used to authenticate endpoints. The `auth:AuthStoreProvider` acts as the interface for all the authentication providers. Any type of implementation such as LDAP, JDBC, and file-based should be object-equivalent. -By default, there are three implementations of the `auth:AuthStoreProvider`. They are; the `auth:ConfigAuthStoreProvider`, - which authenticates based on usernames and passwords stored in a configuration file, the `auth:JWTAuthProvider`, which - authenticates by validating a JWT, and finally the `auth:LdapAuthStoreProvider`, which authenticates based on the user - credentials stored in an active directory or an LDAP. +By default, there are three implementations of the `auth:AuthProvider`. They are: +1. The `auth:ConfigAuthStoreProvider`, which authenticates based on usernames and passwords stored in a configuration file. +2. The `auth:JWTAuthProvider`, which authenticates by validating a JWT. +3. The `auth:LdapAuthStoreProvider`, which authenticates based on the user credentials stored in an active directory or an LDAP. -When creating a new authentication provider, there are two functions that need to be implemented. +When creating a new authentication provider, there is a function that needs to be implemented. - `authenticate` : Authenticates the user based on a credential, which can be username/password, or a token such as JWT. -- `getScopes` : Provides the scopes associated with the user. Scopes are primarily permissions that are required to access a protected resource. ### Config Auth Store Provider -`ConfigAuthStoreProvider` is an implementation of the `AuthStoreProvider` interface, which uses the Ballerina configuration file to store usernames, passwords, scopes and the relevant associations. +The `auth:ConfigAuthStoreProvider` is an implementation of the `auth:AuthProvider` interface, which uses the Ballerina configuration file to store usernames, passwords, scopes, and relevant associations. -A user is denoted by a section in the configuration file. The password and the scopes assigned to the user are denoted as keys under the relevant user section as seen below. +A user is denoted by a section in the configuration file. The password and the scopes assigned to the user are denoted as keys under the relevant user section as shown below. ``` [b7a.users.] @@ -29,5 +28,8 @@ A user is denoted by a section in the configuration file. The password and the s ### LDAP Auth Store Provider -`LdapAuthStoreProvider` is another implementation of the `AuthStoreProvider` interface, which connects to an active -directory or an LDAP to retrieve the necessary user information to perform authentication and authorization. +The `auth:LdapAuthStoreProvider` is another implementation of the `auth:AuthProvider` interface. This connects to an active directory or an LDAP, retrieves the necessary user information, and performs authentication and authorization. + +### JWT Auth Provider + +The `auth:JWTAuthProvider` is another implementation of the `auth:AuthProvider` interface, which authenticates by validating a JWT. diff --git a/stdlib/auth/src/main/ballerina/auth/auth_provider.bal b/stdlib/auth/src/main/ballerina/auth/auth_provider.bal new file mode 100644 index 000000000000..79df104b8a59 --- /dev/null +++ b/stdlib/auth/src/main/ballerina/auth/auth_provider.bal @@ -0,0 +1,26 @@ +// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +# Represents the auth provider. Any type of implementation, such as LDAP, JDBC, file based, etc. +# should be object-wise similar +public type AuthProvider abstract object { + + # Authenticate with credential value passed. + # + # + credential - Credential value + # + return - True if authentication is a success, else false or `error` occurred + public function authenticate(string credential) returns boolean|error; +}; diff --git a/stdlib/auth/src/main/ballerina/auth/auth_store_provider.bal b/stdlib/auth/src/main/ballerina/auth/auth_store_provider.bal deleted file mode 100644 index 30acd6a9c213..000000000000 --- a/stdlib/auth/src/main/ballerina/auth/auth_store_provider.bal +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -// -// WSO2 Inc. licenses this file to you under the Apache License, -// Version 2.0 (the "License"); you may not use this file except -// in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -# Represents the auth store provider. Any type of implementation, such as -# LDAP, JDBC, file based, etc. should be object-wise similar -public type AuthStoreProvider object { - - # Authenticate with username and password - # - # + username - user name - # + password - password - # + return - true if authentication is a success, else false - public function authenticate(string username, string password) returns boolean; - - # Reads the scope(s) for the user with the given username - # - # + username - user name - # + return - array of groups for the user denoted by the username - public function getScopes(string username) returns string[]; -}; - -public function AuthStoreProvider.authenticate(string username, string password) returns boolean { - return true; -} - -public function AuthStoreProvider.getScopes(string username) returns string[] { - string[] val = []; - return val; -} diff --git a/stdlib/auth/src/main/ballerina/auth/config_auth_store_provider.bal b/stdlib/auth/src/main/ballerina/auth/config_auth_store_provider.bal index 21c9863b955f..9c9f603bd6e5 100644 --- a/stdlib/auth/src/main/ballerina/auth/config_auth_store_provider.bal +++ b/stdlib/auth/src/main/ballerina/auth/config_auth_store_provider.bal @@ -21,47 +21,35 @@ import ballerina/runtime; const string CONFIG_USER_SECTION = "b7a.users"; -# Represents configurations that required for Config auth store. -# -public type ConfigAuthProviderConfig record {| -|}; - # Represents Ballerina configuration file based auth store provider. -# -# + configAuthProviderConfig - Config auth store configurations public type ConfigAuthStoreProvider object { - public ConfigAuthProviderConfig configAuthProviderConfig; - - # Create an Config auth store with the given configurations. - # - # + configAuthProviderConfig - Config auth store configurations - public function __init(ConfigAuthProviderConfig configAuthProviderConfig) { - self.configAuthProviderConfig = configAuthProviderConfig; - } + *AuthProvider; - # Attempts to authenticate with username and password. + # Attempts to authenticate with credential. # - # + user - user name - # + password - password - # + return - true if authentication is a success, else false - public function authenticate(string user, string password) returns boolean { - if (user == EMPTY_STRING || password == EMPTY_STRING) { + # + credential - Credential + # + return - `true` if authentication is successful, otherwise `false` or `error` occured while extracting credentials + public function authenticate(string credential) returns boolean|error { + if (credential == EMPTY_STRING) { return false; } - string passwordFromConfig = self.readPassword(user); + string username; + string password; + (username, password) = check extractUsernameAndPassword(credential); + string passwordFromConfig = readPassword(username); boolean isAuthenticated = false; // This check is added to avoid having to go through multiple condition evaluations, when value is plain text. if (passwordFromConfig.hasPrefix(CONFIG_PREFIX)) { if (passwordFromConfig.hasPrefix(CONFIG_PREFIX_SHA256)) { isAuthenticated = encoding:encodeHex(crypto:hashSha256(password.toByteArray(DEFAULT_CHARSET))) - .equalsIgnoreCase(self.extractHash(passwordFromConfig)); + .equalsIgnoreCase(extractHash(passwordFromConfig)); } else if (passwordFromConfig.hasPrefix(CONFIG_PREFIX_SHA384)) { isAuthenticated = encoding:encodeHex(crypto:hashSha384(password.toByteArray(DEFAULT_CHARSET))) - .equalsIgnoreCase(self.extractHash(passwordFromConfig)); + .equalsIgnoreCase(extractHash(passwordFromConfig)); } else if (passwordFromConfig.hasPrefix(CONFIG_PREFIX_SHA512)) { isAuthenticated = encoding:encodeHex(crypto:hashSha512(password.toByteArray(DEFAULT_CHARSET))) - .equalsIgnoreCase(self.extractHash(passwordFromConfig)); + .equalsIgnoreCase(extractHash(passwordFromConfig)); } else { isAuthenticated = password == passwordFromConfig; } @@ -70,53 +58,54 @@ public type ConfigAuthStoreProvider object { } if (isAuthenticated) { runtime:Principal principal = runtime:getInvocationContext().principal; - principal.userId = user; - principal.username = user; + principal.userId = username; + principal.username = username; + principal.scopes = self.getScopes(username); } return isAuthenticated; } - # Extract password hash from the configuration file. - # - # + configValue - config value to extract the password from - # + return - password hash extracted from the configuration field - public function extractHash(string configValue) returns string { - return configValue.substring(configValue.indexOf("{") + 1, configValue.lastIndexOf("}")); - } - # Reads the scope(s) for the user with the given username. # - # + username - username - # + return - array of groups for the user denoted by the username + # + username - Username + # + return - Array of groups for the user denoted by the username public function getScopes(string username) returns string[] { // first read the user id from user->id mapping - // reads the groups for the userid - return self.getArray(self.getConfigAuthValue(CONFIG_USER_SECTION + "." + username, "scopes")); + // reads the groups for the user-id + return getArray(getConfigAuthValue(CONFIG_USER_SECTION + "." + username, "scopes")); } +}; - # Reads the password hash for a user. - # - # + username - username - # + return - password hash read from userstore, or nil if not found - public function readPassword(string username) returns string { - // first read the user id from user->id mapping - // read the hashed password from the userstore file, using the user id - return self.getConfigAuthValue(CONFIG_USER_SECTION + "." + username, "password"); - } +# Extract password hash from the configuration file. +# +# + configValue - Config value to extract the password from +# + return - Password hash extracted from the configuration field +function extractHash(string configValue) returns string { + return configValue.substring(configValue.indexOf("{") + 1, configValue.lastIndexOf("}")); +} - public function getConfigAuthValue(string instanceId, string property) returns string { - return config:getAsString(instanceId + "." + property, defaultValue = ""); - } +# Reads the password hash for a user. +# +# + username - Username +# + return - Password hash read from userstore, or nil if not found +function readPassword(string username) returns string { + // first read the user id from user->id mapping + // read the hashed password from the userstore file, using the user id + return getConfigAuthValue(CONFIG_USER_SECTION + "." + username, "password"); +} - # Construct an array of groups from the comma separed group string passed. - # - # + groupString - comma separated string of groups - # + return - array of groups, nil if the groups string is empty/nil - public function getArray(string groupString) returns (string[]) { - string[] groupsArr = []; - if (groupString.length() == 0) { - return groupsArr; - } - return groupString.split(","); +function getConfigAuthValue(string instanceId, string property) returns string { + return config:getAsString(instanceId + "." + property, defaultValue = ""); +} + +# Construct an array of groups from the comma separed group string passed. +# +# + groupString - Comma separated string of groups +# + return - Array of groups, nil if the groups string is empty/nil +function getArray(string groupString) returns string[] { + string[] groupsArr = []; + if (groupString.length() == 0) { + return groupsArr; } -}; + return groupString.split(","); +} diff --git a/stdlib/auth/src/main/ballerina/auth/jwt_common.bal b/stdlib/auth/src/main/ballerina/auth/jwt/jwt_common.bal similarity index 100% rename from stdlib/auth/src/main/ballerina/auth/jwt_common.bal rename to stdlib/auth/src/main/ballerina/auth/jwt/jwt_common.bal diff --git a/stdlib/auth/src/main/ballerina/auth/jwt_issuer.bal b/stdlib/auth/src/main/ballerina/auth/jwt/jwt_issuer.bal similarity index 88% rename from stdlib/auth/src/main/ballerina/auth/jwt_issuer.bal rename to stdlib/auth/src/main/ballerina/auth/jwt/jwt_issuer.bal index 07abfbb737bf..06ddf80f089b 100644 --- a/stdlib/auth/src/main/ballerina/auth/jwt_issuer.bal +++ b/stdlib/auth/src/main/ballerina/auth/jwt/jwt_issuer.bal @@ -66,19 +66,14 @@ public function issueJwt(JwtHeader header, JwtPayload payload, JWTIssuerConfig? signature = encoding:encodeBase64Url(check crypto:signRsaSha512(jwtAssertion.toByteArray("UTF-8"), privateKey)); } else { - error jwtError = error(AUTH_ERROR_CODE, { message : "Unsupported JWS algorithm" }); - return jwtError; + return prepareError("Unsupported JWS algorithm."); } return (jwtAssertion + "." + signature); } else { - error jwtError = error(AUTH_ERROR_CODE, - { message : "Signing JWT requires keyStore, keyAlias and keyPassword" }); - return jwtError; + return prepareError("Signing JWT requires keyStore, keyAlias and keyPassword."); } } else { - error jwtError = error(AUTH_ERROR_CODE, - { message : "Signing JWT requires JWTIssuerConfig with keystore information" }); - return jwtError; + return prepareError("Signing JWT requires JWTIssuerConfig with keystore information."); } } } @@ -86,8 +81,7 @@ public function issueJwt(JwtHeader header, JwtPayload payload, JWTIssuerConfig? function buildHeaderString(JwtHeader header) returns (string|error) { json headerJson = {}; if (!validateMandatoryJwtHeaderFields(header)) { - error jwtError = error(AUTH_ERROR_CODE, { message : "Mandatory field signing algorithm (alg) is empty." }); - return jwtError; + return prepareError("Mandatory field signing algorithm (alg) is empty."); } if (header.alg == RS256) { headerJson[ALG] = "RS256"; @@ -98,8 +92,7 @@ function buildHeaderString(JwtHeader header) returns (string|error) { } else if (header.alg == NONE) { headerJson[ALG] = "none"; } else { - error jwtError = error(AUTH_ERROR_CODE, { message : "Unsupported JWS algorithm" }); - return jwtError; + return prepareError("Unsupported JWS algorithm."); } headerJson[TYP] = "JWT"; string headerValInString = headerJson.toString(); diff --git a/stdlib/auth/src/main/ballerina/auth/jwt_validator.bal b/stdlib/auth/src/main/ballerina/auth/jwt/jwt_validator.bal similarity index 86% rename from stdlib/auth/src/main/ballerina/auth/jwt_validator.bal rename to stdlib/auth/src/main/ballerina/auth/jwt/jwt_validator.bal index 76d3e510e0b3..336bff7f11bd 100644 --- a/stdlib/auth/src/main/ballerina/auth/jwt_validator.bal +++ b/stdlib/auth/src/main/ballerina/auth/jwt/jwt_validator.bal @@ -68,8 +68,7 @@ public function validateJwt(string jwtToken, JWTValidatorConfig config) returns if (jwtValidity) { return payload; } else { - error jwtError = error(AUTH_ERROR_CODE, { message : "Invalid JWT token" }); - return jwtError; + return prepareError("Invalid JWT token."); } } } @@ -77,8 +76,7 @@ public function validateJwt(string jwtToken, JWTValidatorConfig config) returns function getJWTComponents(string jwtToken) returns (string[])|error { string[] jwtComponents = jwtToken.split("\\."); if (jwtComponents.length() < 2 || jwtComponents.length() > 3) { - error jwtError = error(AUTH_ERROR_CODE, { message : "Invalid JWT token" }); - return jwtError; + return prepareError("Invalid JWT token."); } return jwtComponents; } @@ -196,16 +194,13 @@ function parsePayload(json jwtPayloadJson) returns (JwtPayload) { function validateJwtRecords(string[] encodedJWTComponents, JwtHeader jwtHeader, JwtPayload jwtPayload, JWTValidatorConfig config) returns (boolean|error) { if (!validateMandatoryJwtHeaderFields(jwtHeader)) { - error jwtError = error(AUTH_ERROR_CODE, - { message : "Mandatory field signing algorithm(alg) is empty in the given JSON Web Token." }); - return jwtError; + return prepareError("Mandatory field signing algorithm(alg) is empty in the given JWT."); } if (config["validateCertificate"] is ()) { config.validateCertificate = true; } if (config.validateCertificate == true && !check validateCertificate(config)) { - error jwtError = error(AUTH_ERROR_CODE, { message : "Public key certificate validity period has passed" }); - return jwtError; + return prepareError("Public key certificate validity period has passed."); } var trustStore = config["trustStore"]; if (trustStore is crypto:TrustStore) { @@ -231,15 +226,13 @@ function validateJwtRecords(string[] encodedJWTComponents, JwtHeader jwtHeader, var exp = jwtPayload["exp"]; if (exp is int) { if (!validateExpirationTime(jwtPayload, config)) { - error jwtError = error(AUTH_ERROR_CODE, { message : "JWT token is expired" }); - return jwtError; + return prepareError("JWT token is expired."); } } var nbf = jwtPayload["nbf"]; if (nbf is int) { if (!validateNotBeforeTime(jwtPayload)) { - error jwtError = error(AUTH_ERROR_CODE, { message : "JWT token is used before Not_Before_Time" }); - return jwtError; + return prepareError("JWT token is used before Not_Before_Time."); } } //TODO : Need to validate jwt id (jti) and custom claims. @@ -273,12 +266,10 @@ function validateCertificate(JWTValidatorConfig config) returns boolean|error { function validateSignature(string[] encodedJWTComponents, JwtHeader jwtHeader, JWTValidatorConfig config) returns boolean|error { if (jwtHeader.alg == NONE) { - error jwtError = error(AUTH_ERROR_CODE, { message : "Not a valid JWS. Signature algorithm is NONE." }); - return jwtError; + return prepareError("Not a valid JWS. Signature algorithm is NONE."); } else { if (encodedJWTComponents.length() == 2) { - error jwtError = error(AUTH_ERROR_CODE, { message : "Not a valid JWS. Signature is required." }); - return jwtError; + return prepareError("Not a valid JWS. Signature is required."); } else { string assertion = encodedJWTComponents[0] + "." + encodedJWTComponents[1]; byte[] signPart = check encoding:decodeBase64Url(encodedJWTComponents[2]); @@ -291,8 +282,7 @@ returns boolean|error { } else if (jwtHeader.alg == RS512) { return crypto:verifyRsaSha512Signature(assertion.toByteArray("UTF-8"), signPart, publicKey); } else { - error jwtError = error(AUTH_ERROR_CODE, { message : "Unsupported JWS algorithm" }); - return jwtError; + return prepareError("Unsupported JWS algorithm."); } } } @@ -301,14 +291,11 @@ returns boolean|error { function validateIssuer(JwtPayload jwtPayload, JWTValidatorConfig config) returns error? { var iss = jwtPayload["iss"]; if (iss is string) { - if(jwtPayload.iss != config.issuer) { - error jwtError = error(AUTH_ERROR_CODE, { message : "JWT contained invalid issuer name : " + - jwtPayload.iss }); - return jwtError; + if (jwtPayload.iss != config.issuer) { + return prepareError("JWT contained invalid issuer name : " + jwtPayload.iss); } } else { - error jwtError = error(AUTH_ERROR_CODE, { message : "JWT must contain a valid issuer name" }); - return jwtError; + return prepareError("JWT must contain a valid issuer name."); } } @@ -328,12 +315,10 @@ function validateAudience(JwtPayload jwtPayload, JWTValidatorConfig config) retu } } if (!validationStatus) { - error jwtError = error(AUTH_ERROR_CODE, { message : "Invalid audience" }); - return jwtError; + return prepareError("Invalid audience."); } } else { - error jwtError = error(AUTH_ERROR_CODE, { message : "JWT must contain a valid audience" }); - return jwtError; + return prepareError("JWT must contain a valid audience."); } } diff --git a/stdlib/auth/src/main/ballerina/auth/jwt_auth_provider.bal b/stdlib/auth/src/main/ballerina/auth/jwt_auth_provider.bal index 739a507e9212..71a8487416db 100644 --- a/stdlib/auth/src/main/ballerina/auth/jwt_auth_provider.bal +++ b/stdlib/auth/src/main/ballerina/auth/jwt_auth_provider.bal @@ -19,29 +19,31 @@ import ballerina/log; import ballerina/runtime; import ballerina/time; -# Represents a JWT Authenticator +# Represents a JWT Authenticator. # +# + jwtAuthProviderConfig - JWT auth provider configurations public type JWTAuthProvider object { - JWTAuthProviderConfig jwtAuthProviderConfig; + *AuthProvider; - # Provides authentication based on the provided jwt token + public JWTAuthProviderConfig jwtAuthProviderConfig; + + # Provides authentication based on the provided jwt token. # # + jwtAuthProviderConfig - JWT authentication provider configurations public function __init(JWTAuthProviderConfig jwtAuthProviderConfig) { self.jwtAuthProviderConfig = jwtAuthProviderConfig; } - # Authenticate with a jwt token + # Authenticate with a jwt token. # # + jwtToken - Jwt token extracted from the authentication header - # + return - true if authentication is successful, false otherwise. - # If an error occur during authentication, the error will be returned. + # + return - `true` if authentication is successful, othewise `false` or `error` occured during jwt validation public function authenticate(string jwtToken) returns boolean|error { if (self.jwtAuthProviderConfig.jwtCache.hasKey(jwtToken)) { - var payload = self.authenticateFromCache(jwtToken); + var payload = authenticateFromCache(self.jwtAuthProviderConfig, jwtToken); if (payload is JwtPayload) { - check self.setAuthenticationContext(payload, jwtToken); + setAuthenticationContext(payload, jwtToken); return true; } else { return false; @@ -72,64 +74,13 @@ public type JWTAuthProvider object { var payload = validateJwt(jwtToken, jwtValidatorConfig); if (payload is JwtPayload) { - check self.setAuthenticationContext(payload, jwtToken); - self.addToAuthenticationCache(jwtToken, payload.exp, payload); + setAuthenticationContext(payload, jwtToken); + addToAuthenticationCache(self.jwtAuthProviderConfig, jwtToken, payload.exp, payload); return true; } else { return payload; } } - - function authenticateFromCache(string jwtToken) returns JwtPayload|() { - var cachedJwt = trap self.jwtAuthProviderConfig.jwtCache.get(jwtToken); - if (cachedJwt is CachedJwt) { - // convert to current time and check the expiry time - if (cachedJwt.expiryTime > (time:currentTime().time / 1000)) { - JwtPayload payload = cachedJwt.jwtPayload; - log:printDebug(function() returns string { - return "Authenticate user :" + payload.sub + " from cache"; - }); - return payload; - } else { - self.jwtAuthProviderConfig.jwtCache.remove(jwtToken); - } - } - return (); - } - - function addToAuthenticationCache(string jwtToken, int exp, JwtPayload payload) { - CachedJwt cachedJwt = {jwtPayload : payload, expiryTime : exp}; - self.jwtAuthProviderConfig.jwtCache.put(jwtToken, cachedJwt); - log:printDebug(function() returns string { - return "Add authenticated user :" + payload.sub + " to the cache"; - }); - } - - function setAuthenticationContext(JwtPayload jwtPayload, string jwtToken) returns error? { - runtime:Principal principal = runtime:getInvocationContext().principal; - principal.userId = jwtPayload.iss + ":" + jwtPayload.sub; - // By default set sub as username. - principal.username = jwtPayload.sub; - principal.claims = jwtPayload.customClaims; - if (jwtPayload.customClaims.hasKey(SCOPES)) { - var scopeString = jwtPayload.customClaims[SCOPES]; - if (scopeString is string) { - principal.scopes = scopeString.split(" "); - } else if (scopeString is json[]) { - principal.scopes = check string[].convert(scopeString); - } - } - if (jwtPayload.customClaims.hasKey(USERNAME)) { - var name = jwtPayload.customClaims[USERNAME]; - if (name is string) { - principal.username = name; - } - } - runtime:AuthenticationContext authenticationContext = runtime:getInvocationContext().authenticationContext; - authenticationContext.scheme = AUTH_TYPE_JWT; - authenticationContext.authToken = jwtToken; - } - }; const string SCOPES = "scope"; @@ -137,7 +88,7 @@ const string GROUPS = "groups"; const string USERNAME = "name"; const string AUTH_TYPE_JWT = "jwt"; -# Represents JWT validator configurations +# Represents JWT validator configurations. # # + issuer - Identifier of the token issuer # + audience - Identifier of the token recipients @@ -156,7 +107,7 @@ public type JWTAuthProviderConfig record {| cache:Cache jwtCache = new; |}; -# Represents parsed and cached JWT +# Represents parsed and cached JWT. # # + jwtPayload - Parsed JWT payload # + expiryTime - Expiry time of the JWT @@ -164,3 +115,50 @@ public type CachedJwt record {| JwtPayload jwtPayload; int expiryTime; |}; + +function authenticateFromCache(JWTAuthProviderConfig jwtAuthProviderConfig, string jwtToken) returns JwtPayload? { + var cachedJwt = trap jwtAuthProviderConfig.jwtCache.get(jwtToken); + if (cachedJwt is CachedJwt) { + // convert to current time and check the expiry time + if (cachedJwt.expiryTime > (time:currentTime().time / 1000)) { + JwtPayload payload = cachedJwt.jwtPayload; + log:printDebug(function() returns string { + return "Authenticate user :" + payload.sub + " from cache"; + }); + return payload; + } else { + jwtAuthProviderConfig.jwtCache.remove(jwtToken); + } + } +} + +function addToAuthenticationCache(JWTAuthProviderConfig jwtAuthProviderConfig, string jwtToken, int exp, JwtPayload payload) { + CachedJwt cachedJwt = {jwtPayload : payload, expiryTime : exp}; + jwtAuthProviderConfig.jwtCache.put(jwtToken, cachedJwt); + log:printDebug(function() returns string { + return "Add authenticated user :" + payload.sub + " to the cache"; + }); +} + +function setAuthenticationContext(JwtPayload jwtPayload, string jwtToken) { + runtime:Principal principal = runtime:getInvocationContext().principal; + principal.userId = jwtPayload.iss + ":" + jwtPayload.sub; + // By default set sub as username. + principal.username = jwtPayload.sub; + principal.claims = jwtPayload.customClaims; + if (jwtPayload.customClaims.hasKey(SCOPES)) { + var scopeString = jwtPayload.customClaims[SCOPES]; + if (scopeString is string) { + principal.scopes = scopeString.split(" "); + } + } + if (jwtPayload.customClaims.hasKey(USERNAME)) { + var name = jwtPayload.customClaims[USERNAME]; + if (name is string) { + principal.username = name; + } + } + runtime:AuthenticationContext authenticationContext = runtime:getInvocationContext().authenticationContext; + authenticationContext.scheme = AUTH_TYPE_JWT; + authenticationContext.authToken = jwtToken; +} diff --git a/stdlib/auth/src/main/ballerina/auth/ldap_auth_store_provider.bal b/stdlib/auth/src/main/ballerina/auth/ldap_auth_store_provider.bal index da2f856649f3..2281903cc1f9 100644 --- a/stdlib/auth/src/main/ballerina/auth/ldap_auth_store_provider.bal +++ b/stdlib/auth/src/main/ballerina/auth/ldap_auth_store_provider.bal @@ -41,7 +41,7 @@ import ballerina/runtime; # + retryAttempts - Retry the authentication request if a timeout happened # + secureClientSocket - The SSL configurations for the ldap client socket. This needs to be configured in order to # communicate through ldaps. -public type LdapAuthProviderConfig record {| +public type LdapAuthStoreProviderConfig record {| string domainName; string connectionURL; string connectionName; @@ -74,65 +74,64 @@ public type SecureClientSocket record {| string trustedCertFile = ""; |}; -# Represents Ballerina configuration for LDAP based auth store provider +# Represents Ballerina configuration for LDAP based auth store provider. # -# + ldapAuthProviderConfig - LDAP auth store configurations +# + ldapAuthStoreProviderConfig - LDAP auth store configurations # + instanceId - Endpoint instance id public type LdapAuthStoreProvider object { - public LdapAuthProviderConfig ldapAuthProviderConfig; + *AuthProvider; + + public LdapAuthStoreProviderConfig ldapAuthStoreProviderConfig; public string instanceId; # Create an LDAP auth store with the given configurations. # - # + ldapAuthProviderConfig - LDAP auth store configurations + # + ldapAuthStoreProviderConfig - LDAP auth store configurations # + instanceId - Endpoint instance id - public function __init(LdapAuthProviderConfig ldapAuthProviderConfig, string instanceId) { - self.ldapAuthProviderConfig = ldapAuthProviderConfig; + public function __init(LdapAuthStoreProviderConfig ldapAuthStoreProviderConfig, string instanceId) { + self.ldapAuthStoreProviderConfig = ldapAuthStoreProviderConfig; self.instanceId = instanceId; initLdapConnectionContext(self, instanceId); } - # Authenticate with username and password + # Authenticate with username and password. # - # + username - user name - # + password - password - # + return - true if authentication is a success, else false - public function authenticate(string username, string password) returns boolean { + # + credential - Credential value + # + return - `true` if authentication is successful, otherwise `false` or `error` occured while extracting credentials + public function authenticate(string credential) returns boolean|error { + if (credential == EMPTY_STRING) { + return false; + } + string username; + string password; + (username, password) = check extractUsernameAndPassword(credential); boolean isAuthenticated = self.doAuthenticate(username, password); if (isAuthenticated) { runtime:Principal principal = runtime:getInvocationContext().principal; - principal.userId = self.ldapAuthProviderConfig.domainName + ":" + username; + principal.userId = self.ldapAuthStoreProviderConfig.domainName + ":" + username; // By default set userId as username. principal.username = username; + principal.scopes = self.getScopes(username); } return isAuthenticated; } - # Reads the scope(s) for the user with the given username + # Reads the scope(s) for the user with the given username. # - # + username - username - # + return - array of groups for the user denoted by the username - public function getScopes(string username) returns string[] { - // Reads the groups for the username - return self.getScopesOfUser(username); - } + # + username - Username + # + return - Array of groups for the user denoted by the username + public function getScopes(string username) returns string[] = external; - # Authenticate with username and password + # Authenticate with username and password. # - # + username - user name - # + password - password + # + username - Username + # + password - Password # + return - true if authentication is a success, else false public function doAuthenticate(string username, string password) returns boolean = external; - - # Reads the scope(s) for the user with the given username - # - # + username - username - # + return - array of groups for the user denoted by the username - public function getScopesOfUser(string username) returns string[] = external; }; -# Initailizes LDAP connection context +# Initailizes LDAP connection context. # # + ldapAuthStoreProvider - LdapAuthStoreProvider provider object # + instanceId - Unique id generated to identify an endpoint diff --git a/stdlib/auth/src/main/ballerina/auth/auth_constants.bal b/stdlib/auth/src/main/ballerina/auth/utils.bal similarity index 55% rename from stdlib/auth/src/main/ballerina/auth/auth_constants.bal rename to stdlib/auth/src/main/ballerina/auth/utils.bal index 88352af9ad3c..bd404cd59df4 100644 --- a/stdlib/auth/src/main/ballerina/auth/auth_constants.bal +++ b/stdlib/auth/src/main/ballerina/auth/utils.bal @@ -14,6 +14,8 @@ // specific language governing permissions and limitations // under the License. +import ballerina/encoding; + # Constant for the auth error code. public const AUTH_ERROR_CODE = "{ballerina/auth}AuthError"; @@ -34,3 +36,28 @@ public const string CONFIG_PREFIX_SHA384 = "@sha384:"; # Prefix used to denote that the config value is a SHA-512 hash. public const string CONFIG_PREFIX_SHA512 = "@sha512:"; + +# Extracts the username and password from credential value. +# +# + credential - Credential value +# + return - A `string` tuple with the extracted username and password or `error` occured while extracting credentials +function extractUsernameAndPassword(string credential) returns (string, string)|error { + string decodedHeaderValue = encoding:byteArrayToString(check encoding:decodeBase64(credential)); + string[] decodedCredentials = decodedHeaderValue.split(":"); + if (decodedCredentials.length() != 2) { + return prepareError("Incorrect credential format. Format should be username:password"); + } else { + return (decodedCredentials[0], decodedCredentials[1]); + } +} + +# Log, prepare and return the `error`. +# +# + message - Error message +# + err - `error` instance +# + return - Prepared `error` instance +function prepareError(string message, error? err = ()) returns error { + log:printError(message, err = err); + error preparedError = error(AUTH_ERROR_CODE, { message: message, reason: err.reason() }); + return preparedError; +} diff --git a/stdlib/auth/src/main/java/org/ballerinalang/auth/ldap/LdapConstants.java b/stdlib/auth/src/main/java/org/ballerinalang/auth/ldap/LdapConstants.java index ec61e9b2c01f..aeab73c30e3d 100644 --- a/stdlib/auth/src/main/java/org/ballerinalang/auth/ldap/LdapConstants.java +++ b/stdlib/auth/src/main/java/org/ballerinalang/auth/ldap/LdapConstants.java @@ -56,7 +56,7 @@ public class LdapConstants { public static final String LDAP_CONFIGURATION = "ldapConfiguration"; public static final String LDAP_CONNECTION_SOURCE = "connectionSource"; public static final String LDAP_CONNECTION_CONTEXT = "connectionContext"; - public static final String LDAP_AUTH_PROVIDER_CONFIG = "ldapAuthProviderConfig"; + public static final String LDAP_AUTH_PROVIDER_CONFIG = "ldapAuthStoreProviderConfig"; public static final String ENDPOINT_INSTANCE_ID = "instanceId"; public static final String SECURE_AUTH_STORE_CONFIG = "secureClientSocket"; diff --git a/stdlib/auth/src/main/java/org/ballerinalang/auth/ldap/nativeimpl/GetLdapScopesOfUser.java b/stdlib/auth/src/main/java/org/ballerinalang/auth/ldap/nativeimpl/GetLdapScopesOfUser.java index 0fb38885c8a3..f6411b993411 100644 --- a/stdlib/auth/src/main/java/org/ballerinalang/auth/ldap/nativeimpl/GetLdapScopesOfUser.java +++ b/stdlib/auth/src/main/java/org/ballerinalang/auth/ldap/nativeimpl/GetLdapScopesOfUser.java @@ -56,7 +56,7 @@ */ @BallerinaFunction( orgName = "ballerina", packageName = "auth", - functionName = "LdapAuthStoreProvider.getScopesOfUser", + functionName = "LdapAuthStoreProvider.getScopes", args = {@Argument(name = "username", type = TypeKind.STRING)}, returnType = {@ReturnType(type = TypeKind.ARRAY, elementType = TypeKind.STRING)}, isPublic = true) diff --git a/stdlib/auth/src/test/java/org/ballerinalang/stdlib/auth/ConfigAuthProviderTest.java b/stdlib/auth/src/test/java/org/ballerinalang/stdlib/auth/ConfigAuthProviderTest.java index 6ab4addc99c8..90cddeb4c946 100644 --- a/stdlib/auth/src/test/java/org/ballerinalang/stdlib/auth/ConfigAuthProviderTest.java +++ b/stdlib/auth/src/test/java/org/ballerinalang/stdlib/auth/ConfigAuthProviderTest.java @@ -25,7 +25,6 @@ import org.ballerinalang.model.values.BBoolean; import org.ballerinalang.model.values.BMap; import org.ballerinalang.model.values.BValue; -import org.ballerinalang.model.values.BValueArray; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -80,114 +79,94 @@ public void testCreateConfigAuthProvider() { @Test(description = "Test case for authenticating non-existing user") public void testAuthenticationOfNonExistingUser() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationOfNonExistingUser"); - Assert.assertNotNull(returns); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); + assertFailureOfResults(returns); } @Test(description = "Test case for authenticating with invalid password") public void testAuthenticationOfNonExistingPassword() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationOfNonExistingPassword"); - Assert.assertNotNull(returns); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); + assertFailureOfResults(returns); } @Test(description = "Test case for successful authentication") public void testAuthentication() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthentication"); - Assert.assertNotNull(returns); - Assert.assertTrue(((BBoolean) returns[0]).booleanValue()); - } - - @Test(description = "Test case for reading groups of non-existing user") - public void testReadScopesOfNonExistingUser() { - BValue[] returns = BRunUtil.invoke(compileResult, "testReadScopesOfNonExistingUser"); - Assert.assertNotNull(returns); - Assert.assertEquals(((BValueArray) returns[0]).size(), 0); - } - - @Test(description = "Test case for reading groups of a user") - public void testReadScopesOfUser() { - BValue[] returns = BRunUtil.invoke(compileResult, "testReadScopesOfUser"); - Assert.assertNotNull(returns); - BValueArray groups = ((BValueArray) returns[0]); - Assert.assertEquals(groups.size(), 1); - - Assert.assertEquals(groups.getString(0), "scope1"); + assertSuccessOfResults(returns); } @Test(description = "Test case for unsuccessful authentication when username is empty") public void testAuthenticationWithEmptyUsername() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationWithEmptyUsername"); - Assert.assertNotNull(returns); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); + assertFailureOfResults(returns); } @Test(description = "Test case for unsuccessful authentication when password is empty") public void testAuthenticationWithEmptyPassword() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationWithEmptyPassword"); - Assert.assertNotNull(returns); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); + assertFailureOfResults(returns); } @Test(description = "Test case for unsuccessful authentication when password is empty and username is invalid") public void testAuthenticationWithEmptyPasswordAndInvalidUsername() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationWithEmptyPasswordAndInvalidUsername"); - Assert.assertNotNull(returns); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); + assertFailureOfResults(returns); } @Test(description = "Test case for unsuccessful authentication when username and password are empty") public void testAuthenticationWithEmptyUsernameAndEmptyPassword() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationWithEmptyUsernameAndEmptyPassword"); - Assert.assertNotNull(returns); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); + assertFailureOfResults(returns); } @Test(description = "Test case for successful authentication with sha-256 hashed password") public void testAuthenticationSha256() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationSha256"); - Assert.assertNotNull(returns); - Assert.assertTrue(((BBoolean) returns[0]).booleanValue()); + assertSuccessOfResults(returns); } @Test(description = "Test case for successful authentication with sha-384 hashed password") public void testAuthenticationSha384() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationSha384"); - Assert.assertNotNull(returns); - Assert.assertTrue(((BBoolean) returns[0]).booleanValue()); + assertSuccessOfResults(returns); } @Test(description = "Test case for successful authentication with sha-512 hashed password") public void testAuthenticationSha512() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationSha512"); - Assert.assertNotNull(returns); - Assert.assertTrue(((BBoolean) returns[0]).booleanValue()); + assertSuccessOfResults(returns); } @Test(description = "Test case for successful authentication with plain text password") public void testAuthenticationPlain() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationPlain"); - Assert.assertNotNull(returns); - Assert.assertTrue(((BBoolean) returns[0]).booleanValue()); + assertSuccessOfResults(returns); } @Test(description = "Test case for unsuccessful authentication with sha-512 hashed password, using invalid " + "password") public void testAuthenticationSha512Negative() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationSha512Negative"); - Assert.assertNotNull(returns); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); + assertFailureOfResults(returns); } @Test(description = "Test case for unsuccessful authentication with plain text password, using invalid password") public void testAuthenticationPlainNegative() { BValue[] returns = BRunUtil.invoke(compileResult, "testAuthenticationPlainNegative"); - Assert.assertNotNull(returns); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); + assertFailureOfResults(returns); } @AfterClass public void tearDown() throws IOException { Files.deleteIfExists(secretCopyPath); } + + private void assertSuccessOfResults(BValue[] returns) { + Assert.assertNotNull(returns); + Assert.assertTrue(returns[0] instanceof BBoolean && ((BBoolean) returns[0]).booleanValue()); + } + + private void assertFailureOfResults(BValue[] returns) { + Assert.assertNotNull(returns); + Assert.assertFalse(returns[0] instanceof BBoolean && ((BBoolean) returns[0]).booleanValue()); + } } diff --git a/stdlib/auth/src/test/java/org/ballerinalang/stdlib/auth/jwt/JwtTest.java b/stdlib/auth/src/test/java/org/ballerinalang/stdlib/auth/jwt/JwtTest.java index 0099f3c59195..e216c39073bb 100644 --- a/stdlib/auth/src/test/java/org/ballerinalang/stdlib/auth/jwt/JwtTest.java +++ b/stdlib/auth/src/test/java/org/ballerinalang/stdlib/auth/jwt/JwtTest.java @@ -145,7 +145,7 @@ public void testCompleteValidatorWithNoIssOrSubNegative() { BValue[] returns = BRunUtil.invoke(compileResult, "testValidateJwt", inputBValues); Assert.assertTrue((returns[0]) instanceof BError); Assert.assertEquals(((BMap) ((BError) returns[0]).getDetails()).get(Constants.MESSAGE).stringValue(), - "JWT must contain a valid issuer name"); + "JWT must contain a valid issuer name."); } @Test(priority = 2, description = "Test case for validating JWT token without issuer or subject information, " + @@ -155,7 +155,7 @@ public void testCompleteValidatorWithNoAudOrSubNegative() { BValue[] returns = BRunUtil.invoke(compileResult, "testValidateJwt", inputBValues); Assert.assertTrue((returns[0]) instanceof BError); Assert.assertEquals(((BMap) ((BError) returns[0]).getDetails()).get(Constants.MESSAGE).stringValue(), - "JWT must contain a valid audience"); + "JWT must contain a valid audience."); } @Test(priority = 2, description = "Test case for validating JWT token without issuer or subject information, " + diff --git a/stdlib/auth/src/test/resources/test-src/config_auth_provider_test.bal b/stdlib/auth/src/test/resources/test-src/config_auth_provider_test.bal index bfaf430623a7..1687b7675100 100644 --- a/stdlib/auth/src/test/resources/test-src/config_auth_provider_test.bal +++ b/stdlib/auth/src/test/resources/test-src/config_auth_provider_test.bal @@ -15,83 +15,82 @@ // under the License. import ballerina/auth; +import ballerina/encoding; -function testCreateConfigAuthProvider() returns (auth:ConfigAuthStoreProvider) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); +function testCreateConfigAuthProvider() returns auth:ConfigAuthStoreProvider { + auth:ConfigAuthStoreProvider configAuthStoreProvider = new; return configAuthStoreProvider; } -function testAuthenticationOfNonExistingUser() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("amila", "abc"); +function testAuthenticationOfNonExistingUser() returns boolean|error { + string usernameAndPassword = "amila:abc"; + return authenticate(usernameAndPassword); } -function testAuthenticationOfNonExistingPassword() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("isuru", "xxy"); +function testAuthenticationOfNonExistingPassword() returns boolean|error { + string usernameAndPassword = "isuru:xxy"; + return authenticate(usernameAndPassword); } -function testAuthentication() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("isuru", "xxx"); +function testAuthentication() returns boolean|error { + string usernameAndPassword = "isuru:xxx"; + return authenticate(usernameAndPassword); } -function testReadScopesOfNonExistingUser() returns (string[]) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.getScopes("amila"); +function testAuthenticationWithEmptyUsername() returns boolean|error { + string usernameAndPassword = ":xxx"; + return authenticate(usernameAndPassword); } -function testReadScopesOfUser() returns (string[]) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.getScopes("ishara"); +function testAuthenticationWithEmptyPassword() returns boolean|error { + auth:ConfigAuthStoreProvider configAuthStoreProvider = new; + string usernameAndPassword = "isuru:"; + return authenticate(usernameAndPassword); } -function testAuthenticationWithEmptyUsername() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("", "xxx"); +function testAuthenticationWithEmptyPasswordAndInvalidUsername() returns boolean|error { + auth:ConfigAuthStoreProvider configAuthStoreProvider = new; + string usernameAndPassword = "invalid:"; + return authenticate(usernameAndPassword); } -function testAuthenticationWithEmptyPassword() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("isuru", ""); +function testAuthenticationWithEmptyUsernameAndEmptyPassword() returns boolean|error { + string usernameAndPassword = ":"; + return authenticate(usernameAndPassword); } -function testAuthenticationWithEmptyPasswordAndInvalidUsername() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("invalid", ""); +function testAuthenticationSha256() returns boolean|error { + string usernameAndPassword = "hashedSha256:xxx"; + return authenticate(usernameAndPassword); } -function testAuthenticationWithEmptyUsernameAndEmptyPassword() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("", ""); +function testAuthenticationSha384() returns boolean|error { + string usernameAndPassword = "hashedSha384:xxx"; + return authenticate(usernameAndPassword); } -function testAuthenticationSha256() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("hashedSha256", "xxx"); +function testAuthenticationSha512() returns boolean|error { + string usernameAndPassword = "hashedSha512:xxx"; + return authenticate(usernameAndPassword); } -function testAuthenticationSha384() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("hashedSha384", "xxx"); +function testAuthenticationPlain() returns boolean|error { + string usernameAndPassword = "plain:plainpassword"; + return authenticate(usernameAndPassword); } -function testAuthenticationSha512() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("hashedSha512", "xxx"); +function testAuthenticationSha512Negative() returns boolean|error { + string usernameAndPassword = "hashedSha512:xxx "; + return authenticate(usernameAndPassword); } -function testAuthenticationPlain() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("plain", "plainpassword"); +function testAuthenticationPlainNegative() returns boolean|error { + string usernameAndPassword = "plain:plainpassword "; + return authenticate(usernameAndPassword); } -function testAuthenticationSha512Negative() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("hashedSha512", "xxx "); -} - -function testAuthenticationPlainNegative() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - return configAuthStoreProvider.authenticate("plain", "plainpassword "); +function authenticate(string usernameAndPassword) returns boolean|error { + auth:ConfigAuthStoreProvider configAuthStoreProvider = new; + string credential = encoding:encodeBase64(usernameAndPassword.toByteArray("UTF-8")); + return configAuthStoreProvider.authenticate(credential); } diff --git a/stdlib/http/src/main/ballerina/http/annotation.bal b/stdlib/http/src/main/ballerina/http/annotation.bal index d2cbd8e9b1ff..d85271cf8b16 100644 --- a/stdlib/http/src/main/ballerina/http/annotation.bal +++ b/stdlib/http/src/main/ballerina/http/annotation.bal @@ -28,7 +28,7 @@ # + chunking - Configures the chunking behaviour for the service # + cors - The cross origin resource sharing configurations for the service # + versioning - The version of the service to be used -# + authConfig - Authentication configurations for securing the service +# + auth - Authentication configurations for secure the service public type HttpServiceConfig record {| Listener?[] endpoints = []; string host = "b7a.default"; @@ -37,7 +37,7 @@ public type HttpServiceConfig record {| Chunking chunking = CHUNKING_AUTO; CorsConfig cors = {}; Versioning versioning = {}; - ListenerAuthConfig? authConfig = {}; + ServiceResourceAuth auth?; |}; # Configurations for CORS support. @@ -109,7 +109,7 @@ public annotation WebSocketServiceConfig WSServiceConfig; # + cors - The cross origin resource sharing configurations for the resource. If not set, the resource will inherit the CORS behaviour of the enclosing service. # + transactionInfectable - Allow to participate in the distributed transactions if value is true # + webSocketUpgrade - Annotation to define HTTP to WebSocket upgrade -# + authConfig - Authentication Configs to secure the resource +# + auth - Authentication Configs to secure the resource public type HttpResourceConfig record {| string[] methods = []; string path = ""; @@ -119,7 +119,7 @@ public type HttpResourceConfig record {| CorsConfig cors = {}; boolean transactionInfectable = true; WebSocketUpgradeConfig? webSocketUpgrade = (); - ListenerAuthConfig? authConfig = (); + ServiceResourceAuth auth?; |}; # Resource configuration to upgrade from HTTP to WebSocket. @@ -133,20 +133,13 @@ public type WebSocketUpgradeConfig record {| # Configures the authentication scheme for a service or a resource. # -# + authentication - Enables/disables authentication -# + authProviders - Array of authentication provider IDs -# + scopes - Array of scopes -public type ListenerAuthConfig record {| - Authentication? authentication = (); - string[]? authProviders = (); - string[]? scopes = (); -|}; - -# Can be used for enabling/disabling authentication in an HTTP service. -# # + enabled - Specifies whether authentication is enabled -public type Authentication record {| - boolean enabled = false; +# + authnHandlers - Array of authentication handlers +# + scopes - Array of scopes +public type ServiceResourceAuth record {| + boolean enabled = true; + AuthnHandler[] authnHandlers?; + string[] scopes?; |}; # The annotation which is used to configure an HTTP resource. diff --git a/stdlib/http/src/main/ballerina/http/auth/auth_handler_registry.bal b/stdlib/http/src/main/ballerina/http/auth/auth_handler_registry.bal deleted file mode 100644 index 92be8cfc4c35..000000000000 --- a/stdlib/http/src/main/ballerina/http/auth/auth_handler_registry.bal +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -// -// WSO2 Inc. licenses this file to you under the Apache License, -// Version 2.0 (the "License"); you may not use this file except -// in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -# Representation of the Http Auth Handler Registry. -# -# + httpAuthHandlers - map for auth handlers. key = auth provider id -public type AuthHandlerRegistry object { - - private map httpAuthHandlers; - - public function __init() { - self.httpAuthHandlers = {}; - } - - # Add an HttpAuthnHandler to HttpAuthHandlerRegistry - # - # + id - Auth provider id - # + authnHandler - HttpAuthnHandler instance - public function add(string id, HttpAuthnHandler authnHandler); - - # Retrieves an HttpAuthnHandler from HttpAuthHandlerRegistry which corresponds to the given id - # - # + id - Auth provider id - # + return - HttpAuthnHandler instance or nil if not found - public function get(string id) returns HttpAuthnHandler?; - - # Retrieve the HttpAuthnHandler map - # - # + return - map of HttpAuthnHandler - public function getAll() returns map; - - # Removes a specific authn handler from the HttpAuthnHandler map - public function remove(string id); - - # Removes all authn handler from the HttpAuthnHandler map - public function clear(); -}; - -public function AuthHandlerRegistry.add(string id, HttpAuthnHandler authnHandler) { - self.httpAuthHandlers[id] = authnHandler; -} - -public function AuthHandlerRegistry.get(string id) returns HttpAuthnHandler? { - if (self.httpAuthHandlers.hasKey(id)) { - return self.httpAuthHandlers[id]; - } - return (); -} - -public function AuthHandlerRegistry.getAll() returns map { - return self.httpAuthHandlers; -} - -public function AuthHandlerRegistry.remove(string id) { - _ = self.httpAuthHandlers.remove(id); -} - -public function AuthHandlerRegistry.clear() { - self.httpAuthHandlers.clear(); -} \ No newline at end of file diff --git a/stdlib/http/src/main/ballerina/http/auth/authn_filter.bal b/stdlib/http/src/main/ballerina/http/auth/authn_filter.bal index 01a9e6e51d75..133249669241 100644 --- a/stdlib/http/src/main/ballerina/http/auth/authn_filter.bal +++ b/stdlib/http/src/main/ballerina/http/auth/authn_filter.bal @@ -14,19 +14,18 @@ // specific language governing permissions and limitations // under the License. - import ballerina/auth; import ballerina/reflect; # Representation of the Authentication filter. # -# + authnHandlerChain - The Authentication handler chain +# + authnHandlers - Array of authentication handlers public type AuthnFilter object { - public AuthnHandlerChain authnHandlerChain; + public AuthnHandler[] authnHandlers; - public function __init(AuthnHandlerChain authnHandlerChain) { - self.authnHandlerChain = authnHandlerChain; + public function __init(AuthnHandler[] authnHandlers) { + self.authnHandlers = authnHandlers; } # Request filter method which attempts to authenticated the request. @@ -36,22 +35,18 @@ public type AuthnFilter object { # + context - A filter context # + return - True if the filter succeeds public function filterRequest(Caller caller, Request request, FilterContext context) returns boolean { - // get auth config for this resource - boolean authenticated = false; - var (isSecured, authProviders) = getResourceAuthConfig(context); - if (isSecured) { - // if auth providers are there, use those to authenticate - if (authProviders.length() > 0) { - authenticated = self.authnHandlerChain.handleWithSpecificAuthnHandlers(authProviders, request); + boolean|error authenticated; + var authnHandlers = getAuthnHandlers(context); + if (authnHandlers is AuthnHandler[]) { + authenticated = handleAuthnRequest(authnHandlers, request); + } else { + if (authnHandlers) { + authenticated = handleAuthnRequest(self.authnHandlers, request); } else { - // if not, try to authenticate using any of available authn handlers - authenticated = self.authnHandlerChain.handle(request); + authenticated = true; } - } else { - // not secured, no need to authenticate - return isAuthnSuccesfull(caller, true); } - return isAuthnSuccesfull(caller, authenticated); + return isAuthnSuccessful(caller, authenticated); } public function filterResponse(Response response, FilterContext context) returns boolean { @@ -59,16 +54,50 @@ public type AuthnFilter object { } }; +function handleAuthnRequest(AuthnHandler[] authnHandlers, Request request) returns boolean|error { + error? err = (); + foreach AuthnHandler authnHandler in authnHandlers { + boolean canHandleResponse = authnHandler.canHandle(request); + if (canHandleResponse) { + var handleResponse = authnHandler.handle(request); + if (handleResponse is boolean) { + if (handleResponse) { + // If one of the authenticators from the chain could successfully authenticate the user, it is not + // required to look through other providers. The authenticator chain is using "OR" combination of + // provider results. + return true; + } + } else { + err = handleResponse; + } + } + } + + if (err is error) { + return err; + } + return false; +} + # Verifies if the authentication is successful. If not responds to the user. # # + caller - Caller for outbound HTTP responses -# + authenticated - Authorization status for the request -# + return - Authorization result to indicate if the filter can proceed(true) or not(false) -function isAuthnSuccesfull(Caller caller, boolean authenticated) returns boolean { +# + authenticated - Authentication status for the request, or `error` if error occured +# + return - Authentication result to indicate if the filter can proceed(true) or not(false) +function isAuthnSuccessful(Caller caller, boolean|error authenticated) returns boolean { Response response = new; - if (!authenticated) { - response.statusCode = 401; - response.setTextPayload("Authentication failure"); + response.statusCode = 401; + if (authenticated is boolean) { + if (!authenticated) { + response.setTextPayload("Authentication failure"); + var err = caller->respond(response); + if (err is error) { + panic err; + } + return false; + } + } else { + response.setTextPayload("Authentication failure. " + authenticated.reason()); var err = caller->respond(response); if (err is error) { panic err; @@ -77,86 +106,3 @@ function isAuthnSuccesfull(Caller caller, boolean authenticated) returns boolean } return true; } - -# Checks if the resource is secured. -# -# + context - A filter context -# + return - A tuple of whether the resource is secured and the list of auth provider ids -function getResourceAuthConfig(FilterContext context) returns (boolean, string[]) { - boolean resourceSecured; - string[] authProviderIds = []; - // get authn details from the resource level - ListenerAuthConfig? resourceLevelAuthAnn = getAuthAnnotation(ANN_MODULE, RESOURCE_ANN_NAME, - reflect:getResourceAnnotations(context.serviceRef, context.resourceName)); - ListenerAuthConfig? serviceLevelAuthAnn = getAuthAnnotation(ANN_MODULE, SERVICE_ANN_NAME, - reflect:getServiceAnnotations(context.serviceRef)); - // check if authentication is enabled - resourceSecured = isResourceSecured(resourceLevelAuthAnn, serviceLevelAuthAnn); - // if resource is not secured, no need to check further - if (!resourceSecured) { - return (resourceSecured, authProviderIds); - } - // check if auth providers are given at resource level - var resourceProviders = resourceLevelAuthAnn.authProviders; - if (resourceProviders is string[]) { - authProviderIds = resourceProviders; - } else { - // no auth providers found in resource level, try in service level - var serviceProviders = serviceLevelAuthAnn.authProviders; - if (serviceProviders is string[]) { - authProviderIds = serviceProviders; - } - } - return (resourceSecured, authProviderIds); -} - -function isResourceSecured(ListenerAuthConfig? resourceLevelAuthAnn, ListenerAuthConfig? serviceLevelAuthAnn) - returns boolean { - boolean isSecured; - var resourceAuthn = resourceLevelAuthAnn.authentication; - if (resourceAuthn is Authentication) { - isSecured = resourceAuthn.enabled; - } else { - // if not found at resource level, check in the service level - var serviceAuthn = serviceLevelAuthAnn.authentication; - if (serviceAuthn is Authentication) { - isSecured = serviceAuthn.enabled; - } else { - // if still authentication annotation is nil, means the user has not specified that the service - // should be secured. However since the authn filter has been engaged, need to authenticate. - isSecured = true; - } - } - return isSecured; -} - -# Tries to retrieve the annotation value for authentication hierarchically - first from the resource level and then -# from the service level, if it is not there in the resource level. -# -# + annotationModule - Annotation module name -# + annotationName - Annotation name -# + annData - Array of annotationData instances -# + return - ListenerAuthConfig instance if its defined, else nil -function getAuthAnnotation(string annotationModule, string annotationName, reflect:annotationData[] annData) - returns ListenerAuthConfig? { - if (annData.length() == 0) { - return (); - } - reflect:annotationData|() authAnn = (); - foreach var ann in annData { - if (ann.name == annotationName && ann.moduleName == annotationModule) { - authAnn = ann; - break; - } - } - if (authAnn is reflect:annotationData) { - if (annotationName == RESOURCE_ANN_NAME) { - HttpResourceConfig resourceConfig = authAnn.value; - return resourceConfig.authConfig; - } else if (annotationName == SERVICE_ANN_NAME) { - HttpServiceConfig serviceConfig = authAnn.value; - return serviceConfig.authConfig; - } - } - return (); -} diff --git a/stdlib/http/src/main/ballerina/http/auth/authn_handler.bal b/stdlib/http/src/main/ballerina/http/auth/authn_handler.bal index ac52909c54a8..a30737fe5f18 100644 --- a/stdlib/http/src/main/ballerina/http/auth/authn_handler.bal +++ b/stdlib/http/src/main/ballerina/http/auth/authn_handler.bal @@ -14,23 +14,18 @@ // specific language governing permissions and limitations // under the License. - # Representation of Authentication handler for HTTP traffic. -# -# + name - Name of the http authn handler -public type HttpAuthnHandler abstract object { - - public string name = ""; +public type AuthnHandler abstract object { # Checks if the request can be authenticated with the relevant `HttpAuthnHandler` implementation # # + req - `Request` instance - # + return - true if can be authenticated, else false + # + return - `true` if can be authenticated, else `false` public function canHandle(Request req) returns boolean; # Tries to authenticate the request with the relevant `HttpAuthnHandler` implementation # # + req - `Request` instance - # + return - true if authenticated successfully, else false - public function handle(Request req) returns boolean; + # + return - `true` if authenticated successfully, else `false` or, `error` in case of errors + public function handle(Request req) returns boolean|error; }; diff --git a/stdlib/http/src/main/ballerina/http/auth/authn_handler_chain.bal b/stdlib/http/src/main/ballerina/http/auth/authn_handler_chain.bal deleted file mode 100644 index bb7110526808..000000000000 --- a/stdlib/http/src/main/ballerina/http/auth/authn_handler_chain.bal +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -// -// WSO2 Inc. licenses this file to you under the Apache License, -// Version 2.0 (the "License"); you may not use this file except -// in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - - -import ballerina/auth; -import ballerina/log; - -# Representation of Authentication handler chain -# -# + authHandlerRegistry - `AuthHandlerRegistry` instance -public type AuthnHandlerChain object { - - private AuthHandlerRegistry authHandlerRegistry; - - public function __init(AuthHandlerRegistry authHandlerRegistry) { - self.authHandlerRegistry = authHandlerRegistry; - } - - # Tries to authenticate against any one of the available authentication handlers - # - # + req - `Request` instance - # + return - true if authenticated successfully, else false - public function handle(Request req) returns boolean; - - # Tries to authenticate against a specifc sub set of the authentication handlers, using the given array of auth provider ids - # - # + authProviderIds - array of auth provider ids - # + req - `Request` instance - # + return - true if authenticated successfully, else false - public function handleWithSpecificAuthnHandlers(string[] authProviderIds, Request req) returns boolean; -}; - -public function AuthnHandlerChain.handle(Request req) returns boolean { - foreach var (currentAuthProviderType, currentAuthHandler) in self.authHandlerRegistry.getAll() { - HttpAuthnHandler authnHandler = currentAuthHandler; - if (authnHandler.canHandle(req)) { - log:printDebug(function () returns string { - return "Trying to authenticate with the auth provider: " + currentAuthProviderType; - }); - boolean authnSuccessful = authnHandler.handle(req); - if (authnSuccessful) { - // If one of the authenticators from the chain could successfully authenticate the user, it is not - // required to look through other providers. The authenticator chain is using "OR" combination of - // provider results. - return true; - } - } - } - return false; -} - -public function AuthnHandlerChain.handleWithSpecificAuthnHandlers(string[] authProviderIds, Request req) - returns boolean { - foreach var authProviderId in authProviderIds { - var authnHandler = self.authHandlerRegistry.get(authProviderId); - if (authnHandler is HttpAuthnHandler) { - if (authnHandler.canHandle(req)) { - log:printDebug(function () returns string { - return "Trying to authenticate with the auth provider: " + authProviderId; - }); - boolean authnSuccessful = authnHandler.handle(req); - if (authnSuccessful) { - // If one of the authenticators from the chain could successfully authenticate the user, it is not - // required to look through other providers. The authenticator chain is using "OR" combination of - // provider results. - return true; - } - } - } - } - return false; -} diff --git a/stdlib/http/src/main/ballerina/http/auth/authz_filter.bal b/stdlib/http/src/main/ballerina/http/auth/authz_filter.bal index ec0e247905fd..d71c3b31e7be 100644 --- a/stdlib/http/src/main/ballerina/http/auth/authz_filter.bal +++ b/stdlib/http/src/main/ballerina/http/auth/authz_filter.bal @@ -14,20 +14,22 @@ // specific language governing permissions and limitations // under the License. - import ballerina/auth; import ballerina/cache; import ballerina/reflect; # Representation of the Authorization filter # -# + authzHandler - `HttpAuthzHandler` instance for handling authorization +# + authzHandler - `AuthzHandler` instance for handling authorization +# + scopes - Array of scopes public type AuthzFilter object { - public HttpAuthzHandler authzHandler; + public AuthzHandler authzHandler; + public string[]? scopes; - public function __init(HttpAuthzHandler authzHandler) { + public function __init(AuthzHandler authzHandler, string[]? scopes) { self.authzHandler = authzHandler; + self.scopes = scopes; } # Filter function implementation which tries to authorize the request @@ -37,35 +39,23 @@ public type AuthzFilter object { # + context - `FilterContext` instance # + return - A flag to indicate if the request flow should be continued(true) or aborted(false), a code and a message public function filterRequest(Caller caller, Request request, FilterContext context) returns boolean { - // first check if the resource is marked to be authenticated. If not, no need to authorize. - ListenerAuthConfig? resourceLevelAuthAnn = getAuthAnnotation(ANN_MODULE, RESOURCE_ANN_NAME, - reflect:getResourceAnnotations(context.serviceRef, context.resourceName)); - ListenerAuthConfig? serviceLevelAuthAnn = getAuthAnnotation(ANN_MODULE, SERVICE_ANN_NAME, - reflect:getServiceAnnotations(context.serviceRef)); - if (!isResourceSecured(resourceLevelAuthAnn, serviceLevelAuthAnn)) { - // not secured, no need to authorize - return isAuthzSuccessfull(caller, true); - } - - string[]? scopes = getScopesForResource(resourceLevelAuthAnn, serviceLevelAuthAnn); - boolean authorized; + boolean|error authorized; + var scopes = getScopes(context); if (scopes is string[]) { - if (scopes.length() > 0) { - if (self.authzHandler.canHandle(request)) { - authorized = self.authzHandler.handle(runtime:getInvocationContext().principal.username, - context.serviceName, context.resourceName, request.method, scopes); + authorized = handleAuthzRequest(self.authzHandler, request, context, scopes); + } else { + if (scopes) { + var selfScopes = self.scopes; + if (selfScopes is string[]) { + authorized = handleAuthzRequest(self.authzHandler, request, context, selfScopes); } else { - authorized = false; + authorized = true; } } else { - // scopes are not defined, no need to authorize authorized = true; } - } else { - // scopes are not defined, no need to authorize - authorized = true; } - return isAuthzSuccessfull(caller, authorized); + return isAuthzSuccessful(caller, authorized); } public function filterResponse(Response response, FilterContext context) returns boolean { @@ -73,17 +63,42 @@ public type AuthzFilter object { } }; +function handleAuthzRequest(AuthzHandler authzHandler, Request request, FilterContext context, string[] scopes) returns boolean|error { + boolean|error authorized; + if (scopes.length() > 0) { + var canHandleResponse = authzHandler.canHandle(request); + if (canHandleResponse is boolean && canHandleResponse) { + authorized = authzHandler.handle(runtime:getInvocationContext().principal.username, + context.serviceName, context.resourceName, request.method, scopes); + } else { + authorized = canHandleResponse; + } + } else { + // scopes are not defined, no need to authorize + authorized = true; + } + return authorized; +} + # Verifies if the authorization is successful. If not responds to the user. # # + caller - Caller for outbound HTTP responses -# + authorized - flag to indicate if authorization is successful or not -# + return - A boolean flag to indicate if the request flow should be continued(true) or -# aborted(false) -function isAuthzSuccessfull(Caller caller, boolean authorized) returns boolean { +# + authorized - Authorization status for the request, or `error` if error occured +# + return - Authorization result to indicate if the filter can proceed(true) or not(false) +function isAuthzSuccessful(Caller caller, boolean|error authorized) returns boolean { Response response = new; - if (!authorized) { - response.statusCode = 403; - response.setTextPayload("Authorization failure"); + response.statusCode = 403; + if (authorized is boolean) { + if (!authorized) { + response.setTextPayload("Authorization failure"); + var err = caller->respond(response); + if (err is error) { + panic err; + } + return false; + } + } else { + response.setTextPayload("Authorization failure. " + authorized.reason()); var err = caller->respond(response); if (err is error) { panic err; @@ -92,20 +107,3 @@ function isAuthzSuccessfull(Caller caller, boolean authorized) returns boolean { } return true; } - -# Retrieves the scope for the resource, if any -# -# + resourceLevelAuthAnn - `ListenerAuthConfig` instance denoting resource level auth annotation details -# + serviceLevelAuthAnn - `ListenerAuthConfig` instance denoting service level auth annotation details -# + return - Array of scopes for the given resource or nil of no scopes are defined -function getScopesForResource (ListenerAuthConfig? resourceLevelAuthAnn, ListenerAuthConfig? serviceLevelAuthAnn) - returns (string[]|()) { - if (resourceLevelAuthAnn.scopes is string[]) { - return resourceLevelAuthAnn.scopes; - } else { - if (serviceLevelAuthAnn.scopes is string[]) { - return serviceLevelAuthAnn.scopes; - } - return (); - } -} diff --git a/stdlib/http/src/main/ballerina/http/auth/authz_handler.bal b/stdlib/http/src/main/ballerina/http/auth/authz_handler.bal index 2952559eef46..e9071b77505d 100644 --- a/stdlib/http/src/main/ballerina/http/auth/authz_handler.bal +++ b/stdlib/http/src/main/ballerina/http/auth/authz_handler.bal @@ -14,7 +14,6 @@ // specific language governing permissions and limitations // under the License. - import ballerina/cache; import ballerina/io; import ballerina/log; @@ -22,17 +21,14 @@ import ballerina/runtime; # Representation of Authorization Handler for HTTP # -# + authStoreProvider - `AuthStoreProvider` instance # + positiveAuthzCache - `Cache` instance, which is cache positive authorizations # + negativeAuthzCache - `Cache` instance, which is cache negative authorizations -public type HttpAuthzHandler object { - public auth:AuthStoreProvider authStoreProvider; - public cache:Cache positiveAuthzCache; - public cache:Cache negativeAuthzCache; - - public function __init(auth:AuthStoreProvider authStoreProvider, cache:Cache positiveAuthzCache, - cache:Cache negativeAuthzCache) { - self.authStoreProvider = authStoreProvider; +public type AuthzHandler object { + + public cache:Cache? positiveAuthzCache; + public cache:Cache? negativeAuthzCache; + + public function __init(cache:Cache? positiveAuthzCache, cache:Cache? negativeAuthzCache) { self.positiveAuthzCache = positiveAuthzCache; self.negativeAuthzCache = negativeAuthzCache; } @@ -40,8 +36,8 @@ public type HttpAuthzHandler object { # Checks if the request can be authorized # # + req - `Request` instance - # + return - true if can be authorized, else false - function canHandle(Request req) returns (boolean); + # + return - `true` if can be authorized, else `false`, or `error` if error occured + function canHandle(Request req) returns boolean|error; # Tries to authorize the request # @@ -51,13 +47,13 @@ public type HttpAuthzHandler object { # + method - HTTP method name # + scopes - Array of scopes # + return - true if authorization check is a success, else false - function handle(string username, string serviceName, string resourceName, string method, string[] scopes) - returns boolean; + function handle(string username, string serviceName, string resourceName, string method, string[] scopes) returns boolean; + # Tries to retrieve authorization decision from the cached information, if any # # + authzCacheKey - Cache key # + return - true or false in case of a cache hit, nil in case of a cache miss - function authorizeFromCache(string authzCacheKey) returns (boolean|()); + function authorizeFromCache(string authzCacheKey) returns boolean?; # Cached the authorization result # @@ -66,15 +62,13 @@ public type HttpAuthzHandler object { function cacheAuthzResult(string authzCacheKey, boolean authorized); }; -function HttpAuthzHandler.handle(string username, string serviceName, string resourceName, string method, - string[] scopes) returns boolean { - // first, check in the cache. cache key is ---, +function AuthzHandler.handle(string username, string serviceName, string resourceName, string method, string[] scopes) returns boolean { + // first, check in the cache. cache key is ----, // since different resources can have different scopes - string authzCacheKey = runtime:getInvocationContext().principal.userId + - "-" + serviceName + "-" + resourceName + "-" + method; + string authzCacheKey = runtime:getInvocationContext().principal.userId + "-" + serviceName + "-" + resourceName + "-" + method; string[] authCtxtScopes = runtime:getInvocationContext().principal.scopes; - //TODO: Make sure principal.scopes array is sorted to prevent cache-misses that could happen due to ordering + //TODO: Make sure principal.scopes array is sorted and set to invocation context in order to prevent cache-misses that could happen due to ordering if (authCtxtScopes.length() > 0) { authzCacheKey += "-"; foreach var authCtxtScope in authCtxtScopes { @@ -93,24 +87,9 @@ function HttpAuthzHandler.handle(string username, string serviceName, string res // cache authz result self.cacheAuthzResult(authzCacheKey, authorized); return authorized; - } else { - // no scopes found for user, try to retrieve using the auth provider - string[] scopesFromAuthProvider = self.authStoreProvider.getScopes(username); - if (scopesFromAuthProvider.length() > 0) { - boolean authorized = checkForScopeMatch(scopes, scopesFromAuthProvider, resourceName, method); - // cache authz result - self.cacheAuthzResult(authzCacheKey, authorized); - return authorized; - } else { - self.cacheAuthzResult(authzCacheKey, false); - log:printDebug(function () returns string { - return "No scopes found for user: " + username + " to access resource: " + resourceName + - ", method:" + method; - }); - return false; - } } } + return false; } # Check whether the scopes of the user and scopes of resource matches. @@ -120,8 +99,7 @@ function HttpAuthzHandler.handle(string username, string serviceName, string res # + resourceName - Name of the `resource` # + method - HTTP method name # + return - true if there is a match between resource and user scopes, else false -function checkForScopeMatch (string[] resourceScopes, string[] userScopes, string resourceName, string method) - returns boolean { +function checkForScopeMatch(string[] resourceScopes, string[] userScopes, string resourceName, string method) returns boolean { boolean authorized = matchScopes(resourceScopes, userScopes); if (authorized) { log:printDebug(function () returns string { @@ -135,7 +113,7 @@ function checkForScopeMatch (string[] resourceScopes, string[] userScopes, strin return authorized; } -function HttpAuthzHandler.authorizeFromCache(string authzCacheKey) returns (boolean|()) { +function AuthzHandler.authorizeFromCache(string authzCacheKey) returns boolean? { var positiveCacheResponse = self.positiveAuthzCache.get(authzCacheKey); if (positiveCacheResponse is boolean) { return true; @@ -144,10 +122,9 @@ function HttpAuthzHandler.authorizeFromCache(string authzCacheKey) returns (bool if (negativeCacheResponse is boolean) { return false; } - return (); } -function HttpAuthzHandler.cacheAuthzResult(string authzCacheKey, boolean authorized) { +function AuthzHandler.cacheAuthzResult(string authzCacheKey, boolean authorized) { if (authorized) { self.positiveAuthzCache.put(authzCacheKey, authorized); } else { @@ -157,25 +134,28 @@ function HttpAuthzHandler.cacheAuthzResult(string authzCacheKey, boolean authori # Tries to find a match between the two scope arrays # -# + scopesOfResource - Scopes of resource -# + scopesForRequest - Scopes of the user -# + return - true if there is a match, else false -function matchScopes(string[] scopesOfResource, string[] scopesForRequest) returns boolean { - foreach var scopeForRequest in scopesForRequest { - foreach var scopeOfResource in scopesOfResource { - if (scopeForRequest == scopeOfResource) { - // if that is equal to a group of a scope, authorization passes - return true; +# + resourceScopes - Scopes of resource +# + userScopes - Scopes of the user +# + return - true if resourceScopes is a subset of userScopes, else false +function matchScopes(string[] resourceScopes, string[] userScopes) returns boolean { + foreach var resourceScope in resourceScopes { + boolean matched = false; + foreach var userScope in userScopes { + if (resourceScope == userScope) { + matched = true; + break; } } + if (!matched) { + return false; + } } - return false; + return true; } -function HttpAuthzHandler.canHandle(Request req) returns boolean { +function AuthzHandler.canHandle(Request req) returns boolean|error { if (runtime:getInvocationContext().principal.username.length() == 0) { - log:printError("Username not set in auth context. Unable to authorize"); - return false; + return prepareError("Username not set in auth context. Unable to authorize."); } return true; } diff --git a/stdlib/http/src/main/ballerina/http/auth/basic_authn_handler.bal b/stdlib/http/src/main/ballerina/http/auth/basic_authn_handler.bal index 06525d12fd0b..569f0815a8fd 100644 --- a/stdlib/http/src/main/ballerina/http/auth/basic_authn_handler.bal +++ b/stdlib/http/src/main/ballerina/http/auth/basic_authn_handler.bal @@ -14,91 +14,43 @@ // specific language governing permissions and limitations // under the License. - import ballerina/auth; import ballerina/encoding; import ballerina/log; import ballerina/runtime; -# Authentication cache name. -const string AUTH_CACHE = "basic_auth_cache"; - # Defines Basic Auth handler for HTTP traffic. # -# + name - Authentication handler name -# + authStoreProvider - AuthStoreProvider instance -public type HttpBasicAuthnHandler object { +# + authProvider - AuthProvider instance +public type BasicAuthnHandler object { - public string name = "basic"; - public auth:AuthStoreProvider authStoreProvider = new; - - public function __init(auth:AuthStoreProvider authStoreProvider) { - self.authStoreProvider = authStoreProvider; - } + *AuthnHandler; - # Checks if the provided request can be authenticated with basic auth. - # - # + req - Request object - # + return - `true` if it is possible authenticate with basic auth, else `false` - public function canHandle(Request req) returns (boolean); + public auth:AuthProvider authProvider; - # Intercept requests for authentication. - # - # + req - Request object - # + return - `true` if authentication is a success, else `false` - public function handle(Request req) returns (boolean); + public function __init(auth:AuthProvider authProvider) { + self.authProvider = authProvider; + } }; -public function HttpBasicAuthnHandler.handle(Request req) returns (boolean) { - // extract the header value - var basicAuthHeader = extractBasicAuthHeaderValue(req); - string basicAuthHeaderValue = ""; - if (basicAuthHeader is string) { - basicAuthHeaderValue = basicAuthHeader; - } else { - log:printError("Error in extracting basic authentication header"); - return false; - } - var credentials = extractBasicAuthCredentials(basicAuthHeaderValue); - if (credentials is (string, string)) { - var (username, password) = credentials; - boolean authenticated = self.authStoreProvider.authenticate(username, password); - if (authenticated) { - // set username - runtime:getInvocationContext().principal.username = username; - // read scopes and set to the invocation context - string[] scopes = self.authStoreProvider.getScopes(username); - if (scopes.length() > 0) { - runtime:getInvocationContext().principal.scopes = scopes; - } - } - return authenticated; - } else { - log:printError("Error in decoding basic authentication header", err = credentials); - } - return false; +# Checks if the provided request can be authenticated with basic auth. +# +# + req - Request object +# + return - `true` if it is possible authenticate with basic auth, else `false`, or `error` in case of errors +public function BasicAuthnHandler.handle(Request req) returns boolean|error { + string basicAuthHeader = extractAuthorizationHeaderValue(req); + string credential = basicAuthHeader.substring(5, basicAuthHeader.length()).trim(); + return self.authProvider.authenticate(credential); } -public function HttpBasicAuthnHandler.canHandle(Request req) returns (boolean) { - var basicAuthHeader = trap req.getHeader(AUTH_HEADER); - if (basicAuthHeader is string) { +# Intercept requests for authentication. +# +# + req - Request object +# + return - `true` if authentication is a success, else `false` +public function BasicAuthnHandler.canHandle(Request req) returns boolean { + if (req.hasHeader(AUTH_HEADER)) { + string basicAuthHeader = extractAuthorizationHeaderValue(req); return basicAuthHeader.hasPrefix(AUTH_SCHEME_BASIC); } return false; } - -# Extracts the basic authentication credentials from the header value. -# -# + authHeader - Basic authentication header -# + return - A `string` tuple with the extracted username and password or `error` that occured while extracting credentials -function extractBasicAuthCredentials(string authHeader) returns (string, string)|error { - // extract user credentials from basic auth header - string decodedBasicAuthHeader = encoding:byteArrayToString(check - encoding:decodeBase64(authHeader.substring(5, authHeader.length()).trim())); - string[] decodedCredentials = decodedBasicAuthHeader.split(":"); - if (decodedCredentials.length() != 2) { - return handleError("Incorrect basic authentication header format"); - } else { - return (decodedCredentials[0], decodedCredentials[1]); - } -} diff --git a/stdlib/http/src/main/ballerina/http/auth/jwt_authn_handler.bal b/stdlib/http/src/main/ballerina/http/auth/jwt_authn_handler.bal index a0769a5cda0b..e563145b1715 100644 --- a/stdlib/http/src/main/ballerina/http/auth/jwt_authn_handler.bal +++ b/stdlib/http/src/main/ballerina/http/auth/jwt_authn_handler.bal @@ -19,70 +19,52 @@ import ballerina/log; # Representation of JWT Auth handler for HTTP traffic # -# + name - Name of the auth handler -# + jwtAuthenticator - `JWTAuthenticator` instance -public type HttpJwtAuthnHandler object { +# + authProvider - `JWTAuthProvider` instance +public type JwtAuthnHandler object { - public string name = "jwt"; - public auth:JWTAuthProvider jwtAuthenticator; + *AuthnHandler; - public function __init(auth:JWTAuthProvider jwtAuthenticator) { - self.jwtAuthenticator = jwtAuthenticator; - } - - # Checks if the request can be authenticated with JWT - # - # + req - `Request` instance - # + return - true if can be authenticated, else false - public function canHandle(Request req) returns boolean; - - # Authenticates the incoming request using JWT authentication - # - # + req - `Request` instance - # + return - true if authenticated successfully, else false - public function handle(Request req) returns boolean; -}; + public auth:AuthProvider authProvider; -public function HttpJwtAuthnHandler.canHandle(Request req) returns boolean { - string authHeader = ""; - var headerValue = trap req.getHeader(AUTH_HEADER); - if (headerValue is string) { - authHeader = headerValue; - } else { - string reason = headerValue.reason(); - log:printDebug(function () returns string { - return "Error in retrieving header " + AUTH_HEADER + ": " + reason; - }); - return false; + public function __init(auth:AuthProvider authProvider) { + self.authProvider = authProvider; } +}; - if (authHeader.hasPrefix(AUTH_SCHEME_BEARER)) { - string[] authHeaderComponents = authHeader.split(" "); - if (authHeaderComponents.length() == 2) { - string[] jwtComponents = authHeaderComponents[1].split("\\."); - if (jwtComponents.length() == 3) { - return true; +# Checks if the request can be authenticated with JWT +# +# + req - `Request` instance +# + return - `true` if can be authenticated, else `false` +public function JwtAuthnHandler.canHandle(Request req) returns boolean { + if (req.hasHeader(AUTH_HEADER)) { + string headerValue = extractAuthorizationHeaderValue(req); + if (headerValue.hasPrefix(AUTH_SCHEME_BEARER)) { + string[] authHeaderComponents = headerValue.split(" "); + if (authHeaderComponents.length() == 2) { + string[] jwtComponents = authHeaderComponents[1].split("\\."); + if (jwtComponents.length() == 3) { + return true; + } } } } return false; } -public function HttpJwtAuthnHandler.handle(Request req) returns boolean { +# Authenticates the incoming request using JWT authentication +# +# + req - `Request` instance +# + return - `true` if authenticated successfully, else `false`, or `error` in case of errors +public function JwtAuthnHandler.handle(Request req) returns boolean|error { string jwtToken = extractJWTToken(req); - var authenticated = self.jwtAuthenticator.authenticate(jwtToken); + var authenticated = self.authProvider.authenticate(jwtToken); if (authenticated is boolean) { return authenticated; } else { - log:printError("Error while validating JWT token ", err = authenticated); + return prepareError("Error while validating JWT token"); } - return false; } -# Extracts the JWT from the incoming request -# -# + req - `Request` instance -# + return - Extracted JWT string function extractJWTToken(Request req) returns string { string authHeader = req.getHeader(AUTH_HEADER); string[] authHeaderComponents = authHeader.split(" "); diff --git a/stdlib/http/src/main/ballerina/http/auth/utils.bal b/stdlib/http/src/main/ballerina/http/auth/utils.bal index fa2cd0a82690..0851350a77e2 100644 --- a/stdlib/http/src/main/ballerina/http/auth/utils.bal +++ b/stdlib/http/src/main/ballerina/http/auth/utils.bal @@ -14,6 +14,9 @@ // specific language governing permissions and limitations // under the License. +import ballerina/log; +import ballerina/reflect; + # Auth annotation module. const string ANN_MODULE = "ballerina/http"; # Resource level annotation name. @@ -40,37 +43,154 @@ public const OAUTH2 = "OAUTH2"; # JWT authentication scheme. public const JWT_AUTH = "JWT_AUTH"; -# Authentication storage providers for BasicAuth scheme. -public type AuthStoreProvider CONFIG_AUTH_STORE|LDAP_AUTH_STORE; - -# Configuration file based authentication storage. -public const CONFIG_AUTH_STORE = "CONFIG_AUTH_STORE"; -# LDAP based authentication storage. -public const LDAP_AUTH_STORE = "LDAP_AUTH_STORE"; - -# Extracts the basic authentication header value from the request. +# Extracts the Authorization header value from the request. # # + req - Request instance -# + return - Value of the basic authentication header, or nil if not found -public function extractBasicAuthHeaderValue(Request req) returns (string|()) { +# + return - Value of the Authorization header +public function extractAuthorizationHeaderValue(Request req) returns string { // extract authorization header - var headerValue = trap req.getHeader(AUTH_HEADER); - if (headerValue is string) { - return headerValue; - } else { - string reason = headerValue.reason(); - log:printDebug(function () returns string { - return "Error in retrieving header " + AUTH_HEADER + ": " + reason; - }); + return req.getHeader(AUTH_HEADER); +} + +# Tries to retrieve the authentication handlers hierarchically - first from the resource level and then +# from the service level, if it is not there in the resource level. +# +# + context - `FilterContext` instance +# + return - Authentication handlers or whether it is needed to engage listener level handlers or not +function getAuthnHandlers(FilterContext context) returns AuthnHandler[]|boolean { + ServiceResourceAuth? resourceLevelAuthAnn; + ServiceResourceAuth? serviceLevelAuthAnn; + (resourceLevelAuthAnn, serviceLevelAuthAnn) = getServiceResourceAuthConfig(context); + + // check if authentication is enabled for resource and service + boolean resourceSecured = isServiceResourceSecured(resourceLevelAuthAnn); + boolean serviceSecured = isServiceResourceSecured(serviceLevelAuthAnn); + + // if resource is not secured, no need to check further + if (!resourceSecured) { + log:printWarn("Resource is not secured. `enabled: false`."); + return false; + } + // check if auth providers are given at resource level + if (resourceLevelAuthAnn is ServiceResourceAuth) { + var resourceAuthHandlers = resourceLevelAuthAnn["authnHandlers"]; + if (resourceAuthHandlers is AuthnHandler[]) { + if (resourceAuthHandlers.length() > 0) { + return resourceAuthHandlers; + } + } + } + + // if service is not secured, no need to check further + if (!serviceSecured) { + log:printWarn("Service is not secured. `enabled: false`."); + return true; + } + // no auth providers found in resource level, try in service level + if (serviceLevelAuthAnn is ServiceResourceAuth) { + var serviceAuthHandlers = serviceLevelAuthAnn["authnHandlers"]; + if (serviceAuthHandlers is AuthnHandler[]) { + if (serviceAuthHandlers.length() > 0) { + return serviceAuthHandlers; + } + } + } + return true; +} + +# Tries to retrieve the authorization scopes hierarchically - first from the resource level and then +# from the service level, if it is not there in the resource level. +# +# + context - `FilterContext` instance +# + return - Authorization scopes or whether it is needed to engage listener level scopes or not +function getScopes(FilterContext context) returns string[]|boolean { + ServiceResourceAuth? resourceLevelAuthAnn; + ServiceResourceAuth? serviceLevelAuthAnn; + (resourceLevelAuthAnn, serviceLevelAuthAnn) = getServiceResourceAuthConfig(context); + + // check if authentication is enabled for resource and service + boolean resourceSecured = isServiceResourceSecured(resourceLevelAuthAnn); + boolean serviceSecured = isServiceResourceSecured(serviceLevelAuthAnn); + + // if resource is not secured, no need to check further + if (!resourceSecured) { + return false; + } + // check if auth providers are given at resource level + if (resourceLevelAuthAnn is ServiceResourceAuth) { + var resourceScopes = resourceLevelAuthAnn["scopes"]; + if (resourceScopes is string[]) { + if (resourceScopes.length() > 0) { + return resourceScopes; + } + } + } + + // if service is not secured, no need to check further + if (!serviceSecured) { + return true; + } + // no auth providers found in resource level, try in service level + if (serviceLevelAuthAnn is ServiceResourceAuth) { + var serviceScopes = serviceLevelAuthAnn["scopes"]; + if (serviceScopes is string[]) { + if (serviceScopes.length() > 0) { + return serviceScopes; + } + } + } + return true; +} + +# Retrieve the authentication annotation value for resource level and service level. +# +# + context - `FilterContext` instance +# + return - Resource level and service level authentication annotations +function getServiceResourceAuthConfig(FilterContext context) returns (ServiceResourceAuth?, ServiceResourceAuth?) { + // get authn details from the resource level + ServiceResourceAuth? resourceLevelAuthAnn = getAuthAnnotation(ANN_MODULE, RESOURCE_ANN_NAME, + reflect:getResourceAnnotations(context.serviceRef, context.resourceName)); + ServiceResourceAuth? serviceLevelAuthAnn = getAuthAnnotation(ANN_MODULE, SERVICE_ANN_NAME, + reflect:getServiceAnnotations(context.serviceRef)); + return (resourceLevelAuthAnn, serviceLevelAuthAnn); +} + +# Retrieves and return the auth annotation with the given module name, annotation name and annotation data. +# +# + annotationModule - Annotation module name +# + annotationName - Annotation name +# + annData - Array of annotationData instances +# + return - `ServiceResourceAuth` instance if its defined, else nil +function getAuthAnnotation(string annotationModule, string annotationName, reflect:annotationData[] annData) returns ServiceResourceAuth? { + if (annData.length() == 0) { + return (); + } + reflect:annotationData? authAnn = (); + foreach var ann in annData { + if (ann.name == annotationName && ann.moduleName == annotationModule) { + authAnn = ann; + break; + } + } + if (authAnn is reflect:annotationData) { + if (annotationName == RESOURCE_ANN_NAME) { + HttpResourceConfig resourceConfig = authAnn.value; + return resourceConfig["auth"]; + } else if (annotationName == SERVICE_ANN_NAME) { + HttpServiceConfig serviceConfig = authAnn.value; + return serviceConfig["auth"]; + } } - return (); } -# Error handler. +# Check for the service or the resource is secured by evaluating the enabled flag configured by the user. # -# + message - Error message -# + return - Error populated with the message -function handleError(string message) returns (error) { - error e = error(message); - return e; +# + serviceResourceAuth - Service or resource auth annotation +# + return - Whether the service or resource secured or not +function isServiceResourceSecured(ServiceResourceAuth? serviceResourceAuth) returns boolean { + boolean secured = true; + if (serviceResourceAuth is ServiceResourceAuth) { + secured = serviceResourceAuth.enabled; + } + return secured; } diff --git a/stdlib/http/src/main/ballerina/http/client_endpoint.bal b/stdlib/http/src/main/ballerina/http/client_endpoint.bal index 584439bd893e..2b18550a86c7 100644 --- a/stdlib/http/src/main/ballerina/http/client_endpoint.bal +++ b/stdlib/http/src/main/ballerina/http/client_endpoint.bal @@ -241,7 +241,7 @@ public type ClientEndpointConfig record {| SecureSocket? secureSocket = (); CacheConfig cache = {}; Compression compression = COMPRESSION_AUTO; - AuthConfig? auth = (); + OutboundAuthConfig? auth = (); |}; @@ -319,11 +319,11 @@ public type ProxyConfig record {| string password = ""; |}; -# The `AuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint. +# The `OutboundAuthConfig` record can be used to configure the authentication mechanism used by the HTTP endpoint. # # + scheme - Authentication scheme # + config - Configuration related to the selected authenticator. -public type AuthConfig record {| +public type OutboundAuthConfig record {| OutboundAuthScheme scheme; BasicAuthConfig|OAuth2AuthConfig|JwtAuthConfig config?; |}; diff --git a/stdlib/http/src/main/ballerina/http/http_secure_client.bal b/stdlib/http/src/main/ballerina/http/http_secure_client.bal index 89ae142afe97..22bb5ee1604d 100644 --- a/stdlib/http/src/main/ballerina/http/http_secure_client.bal +++ b/stdlib/http/src/main/ballerina/http/http_secure_client.bal @@ -336,7 +336,7 @@ public type HttpSecureClient client object { # + return - Created secure HTTP client public function createHttpSecureClient(string url, ClientEndpointConfig config) returns Client|error { HttpSecureClient httpSecureClient; - if (config.auth is AuthConfig) { + if (config.auth is OutboundAuthConfig) { httpSecureClient = new(url, config); return httpSecureClient; } else { @@ -354,7 +354,7 @@ public function createHttpSecureClient(string url, ClientEndpointConfig config) # `error` if an error occurred during the HTTP client invocation function generateSecureRequest(Request req, ClientEndpointConfig config, CachedToken tokenCache) returns boolean|error { var auth = config.auth; - if (auth is AuthConfig) { + if (auth is OutboundAuthConfig) { var authConfig = auth["config"]; if (auth.scheme == BASIC_AUTH) { if (authConfig is BasicAuthConfig) { @@ -906,7 +906,7 @@ function updateTokenCache(json responsePayload, CachedToken tokenCache, int cloc function isRetryRequired(boolean retryRequired, Response res, ClientEndpointConfig config) returns boolean { if (retryRequired && res.statusCode == UNAUTHORIZED_401) { var auth = config.auth; - if (auth is AuthConfig) { + if (auth is OutboundAuthConfig) { var authConfig = auth.config; if (auth.scheme == OAUTH2 && authConfig is OAuth2AuthConfig) { var grantType = authConfig.grantType; @@ -935,7 +935,7 @@ function isRetryRequired(boolean retryRequired, Response res, ClientEndpointConf # + return - Returns `error` if an error occurred during the HTTP client invocation function updateRequest(Request req, ClientEndpointConfig config, CachedToken tokenCache) returns error? { var auth = config.auth; - if (auth is AuthConfig) { + if (auth is OutboundAuthConfig) { var authConfig = auth.config; if (authConfig is OAuth2AuthConfig) { string authToken; diff --git a/stdlib/http/src/main/ballerina/http/resiliency/failover_client_endpoint.bal b/stdlib/http/src/main/ballerina/http/resiliency/failover_client_endpoint.bal index b25f51b24031..e1d68ec4002c 100644 --- a/stdlib/http/src/main/ballerina/http/resiliency/failover_client_endpoint.bal +++ b/stdlib/http/src/main/ballerina/http/resiliency/failover_client_endpoint.bal @@ -466,7 +466,7 @@ public type FailoverClientEndpointConfiguration record {| TargetService[] targets = []; CacheConfig cache = {}; Compression compression = COMPRESSION_AUTO; - AuthConfig? auth = (); + OutboundAuthConfig? auth = (); int[] failoverCodes = [501, 502, 503, 504]; int intervalMillis = 0; |}; diff --git a/stdlib/http/src/main/ballerina/http/resiliency/load_balance_client_endpoint.bal b/stdlib/http/src/main/ballerina/http/resiliency/load_balance_client_endpoint.bal index 6de67f220118..16fd4dc5e06f 100644 --- a/stdlib/http/src/main/ballerina/http/resiliency/load_balance_client_endpoint.bal +++ b/stdlib/http/src/main/ballerina/http/resiliency/load_balance_client_endpoint.bal @@ -354,7 +354,7 @@ public type LoadBalanceClientEndpointConfiguration record {| TargetService[] targets = []; CacheConfig cache = {}; Compression compression = COMPRESSION_AUTO; - AuthConfig? auth = (); + OutboundAuthConfig? auth = (); LoadBalancerRule? lbRule = (); boolean failover = true; |}; diff --git a/stdlib/http/src/main/ballerina/http/service_endpoint.bal b/stdlib/http/src/main/ballerina/http/service_endpoint.bal index 539b3a96fe9b..d40cf8616e69 100644 --- a/stdlib/http/src/main/ballerina/http/service_endpoint.bal +++ b/stdlib/http/src/main/ballerina/http/service_endpoint.bal @@ -74,13 +74,12 @@ public type Listener object { public function Listener.init(ServiceEndpointConfiguration c) { self.config = c; - var authProviders = self.config.authProviders; - if (authProviders is AuthProvider[]) { - var providers = authProviders; - if (providers.length() > 0) { + var auth = self.config["auth"]; + if (auth is ListenerAuth) { + if (auth.authnHandlers.length() > 0) { var secureSocket = self.config.secureSocket; if (secureSocket is ServiceSecureSocket) { - addAuthFiltersForSecureListener(self.config, self.instanceId); + addAuthFiltersForSecureListener(self.config); } else { error err = error("Secure sockets have not been cofigured in order to enable auth providers."); panic err; @@ -141,19 +140,29 @@ public type RequestLimits record {| # + maxPipelinedRequests - Defines the maximum number of requests that can be processed at a given time on a single # connection. By default 10 requests can be pipelined on a single cinnection and user can # change this limit appropriately. This will be applicable only for HTTP 1.1 -# + authProviders - The array of authentication providers which are used to authenticate the users -# + positiveAuthzCache - Caching configurations for positive authorizations -# + negativeAuthzCache - Caching configurations for negative authorizations +# + auth - Listener authenticaton configurations public type ServiceEndpointConfiguration record {| string host = "0.0.0.0"; KeepAlive keepAlive = KEEPALIVE_AUTO; ServiceSecureSocket? secureSocket = (); string httpVersion = "1.1"; RequestLimits? requestLimits = (); + //TODO: update as a optional field Filter[] filters = []; int timeoutMillis = DEFAULT_LISTENER_TIMEOUT; int maxPipelinedRequests = MAX_PIPELINED_REQUESTS; - AuthProvider[]? authProviders = (); + ListenerAuth auth?; +|}; + +# Authentication configurations for the listener. +# +# + authnHandlers - Array of authentication handlers +# + scopes - Array of scopes +# + positiveAuthzCache - Caching configurations for positive authorizations +# + negativeAuthzCache - Caching configurations for negative authorizations +public type ListenerAuth record {| + AuthnHandler[] authnHandlers; + string[] scopes?; AuthCacheConfig positiveAuthzCache = {}; AuthCacheConfig negativeAuthzCache = {}; |}; @@ -210,19 +219,6 @@ public type AuthCacheConfig record {| float evictionFactor = 1; |}; -# Configuration for authentication providers. -# -# + id - Authentication provider instance id -# + scheme - Authentication scheme -# + authStoreProvider - Authentication store provider (Config, LDAP, etc.) implementation -# + config - Configuration related to the selected authentication provider. -public type AuthProvider record {| - string id = ""; - InboundAuthScheme? scheme = (); - AuthStoreProvider? authStoreProvider = (); - auth:LdapAuthProviderConfig|auth:ConfigAuthProviderConfig|auth:JWTAuthProviderConfig? config = (); -|}; - # Defines the possible values for the keep-alive configuration in service and client endpoints. public type KeepAlive KEEPALIVE_AUTO|KEEPALIVE_ALWAYS|KEEPALIVE_NEVER; @@ -236,130 +232,43 @@ public const KEEPALIVE_NEVER = "NEVER"; # Add authn and authz filters # # + config - `ServiceEndpointConfiguration` instance -# + instanceId - Endpoint instance id -function addAuthFiltersForSecureListener(ServiceEndpointConfiguration config, string instanceId) { +function addAuthFiltersForSecureListener(ServiceEndpointConfiguration config) { // add authentication and authorization filters as the first two filters. // if there are any other filters specified, those should be added after the authn and authz filters. - if (config.filters.length() == 0) { - // can add authn and authz filters directly - config.filters = createAuthFiltersForSecureListener(config, instanceId); - } else { - Filter[] newFilters = createAuthFiltersForSecureListener(config, instanceId); - // add existing filters next - int i = 0; - while (i < config.filters.length()) { - newFilters[i + (newFilters.length())] = config.filters[i]; - i = i + 1; - } - config.filters = newFilters; - } -} - -# Create an array of auth and authz filters. -# -# + config - `ServiceEndpointConfiguration` instance -# + instanceId - Endpoint instance id -# + return - Array of Filters comprising of authn and authz Filters -function createAuthFiltersForSecureListener(ServiceEndpointConfiguration config, string instanceId) returns (Filter[]) { - // parse and create authentication handlers - AuthHandlerRegistry registry = new; Filter[] authFilters = []; - var authProviderList = config.authProviders; - if (authProviderList is AuthProvider[]) { - if (authProviderList.length() > 0) { - foreach var provider in authProviderList { - if (provider.id.length() > 0) { - registry.add(provider.id, createAuthHandler(provider, instanceId)); - } else { - string providerId = system:uuid(); - registry.add(providerId, createAuthHandler(provider, instanceId)); - } - } - - AuthnHandlerChain authnHandlerChain = new(registry); - AuthnFilter authnFilter = new(authnHandlerChain); - cache:Cache positiveAuthzCache = new(expiryTimeMillis = config.positiveAuthzCache.expiryTimeMillis, - capacity = config.positiveAuthzCache.capacity, - evictionFactor = config.positiveAuthzCache.evictionFactor); - cache:Cache negativeAuthzCache = new(expiryTimeMillis = config.negativeAuthzCache.expiryTimeMillis, - capacity = config.negativeAuthzCache.capacity, - evictionFactor = config.negativeAuthzCache.evictionFactor); - auth:AuthStoreProvider authStoreProvider = new; - - foreach var provider in authProviderList { - var authProviderConfig = provider.config; - if (provider.scheme == BASIC_AUTH) { - if (provider.authStoreProvider == LDAP_AUTH_STORE) { - if (authProviderConfig is auth:LdapAuthProviderConfig) { - auth:LdapAuthStoreProvider ldapAuthStoreProvider = new(authProviderConfig, instanceId); - authStoreProvider = ldapAuthStoreProvider; - } else { - error e = error("LDAP auth provider config not provided"); - panic e; - } - } else if (provider.authStoreProvider == CONFIG_AUTH_STORE) { - auth:ConfigAuthStoreProvider configAuthStoreProvider; - if (authProviderConfig is auth:ConfigAuthProviderConfig) { - configAuthStoreProvider = new(authProviderConfig); - } else { - configAuthStoreProvider = new({}); - } - authStoreProvider = configAuthStoreProvider; - } else { - error configError = error("Unsupported auth store provider"); - panic configError; - } - } - } - - HttpAuthzHandler authzHandler = new(authStoreProvider, positiveAuthzCache, negativeAuthzCache); - AuthzFilter authzFilter = new(authzHandler); - authFilters[0] = authnFilter; - authFilters[1] = authzFilter; - } - } - return authFilters; -} -function createAuthHandler(AuthProvider authProvider, string instanceId) returns HttpAuthnHandler { - var authProviderConfig = authProvider.config; - if (authProvider.scheme == BASIC_AUTH) { - auth:AuthStoreProvider authStoreProvider = new; - if (authProvider.authStoreProvider == CONFIG_AUTH_STORE) { - auth:ConfigAuthStoreProvider configAuthStoreProvider; - if (authProviderConfig is auth:ConfigAuthProviderConfig) { - configAuthStoreProvider = new(authProviderConfig); - } else { - configAuthStoreProvider = new({}); - } - authStoreProvider = configAuthStoreProvider; - } else if (authProvider.authStoreProvider == LDAP_AUTH_STORE) { - if (authProviderConfig is auth:LdapAuthProviderConfig) { - auth:LdapAuthStoreProvider ldapAuthStoreProvider = new(authProviderConfig, instanceId); - authStoreProvider = ldapAuthStoreProvider; - } else { - error e = error("LDAP auth provider config not provided"); - panic e; - } + var auth = config["auth"]; + if (auth is ListenerAuth) { + AuthnHandler[] authnHandlers = auth.authnHandlers; + AuthnFilter authnFilter = new(authnHandlers); + authFilters[0] = authnFilter; + + var scopes = auth["scopes"]; + cache:Cache positiveAuthzCache = new(expiryTimeMillis = auth.positiveAuthzCache.expiryTimeMillis, + capacity = auth.positiveAuthzCache.capacity, + evictionFactor = auth.positiveAuthzCache.evictionFactor); + cache:Cache negativeAuthzCache = new(expiryTimeMillis = auth.negativeAuthzCache.expiryTimeMillis, + capacity = auth.negativeAuthzCache.capacity, + evictionFactor = auth.negativeAuthzCache.evictionFactor); + AuthzHandler authzHandler = new(positiveAuthzCache, negativeAuthzCache); + AuthzFilter authzFilter = new(authzHandler, scopes); + authFilters[1] = authzFilter; + + if (config.filters.length() == 0) { + // can add authn and authz filters directly + config.filters = authFilters; } else { - error e = error("Unsupported auth store provider"); - panic e; - } - HttpBasicAuthnHandler basicAuthHandler = new(authStoreProvider); - return basicAuthHandler; - } else if (authProvider.scheme == JWT_AUTH){ - if (authProviderConfig is auth:JWTAuthProviderConfig) { - auth:JWTAuthProvider jwtAuthProvider = new(authProviderConfig); - HttpJwtAuthnHandler jwtAuthnHandler = new(jwtAuthProvider); - return jwtAuthnHandler; - } else { - error e = error("JWT auth provider config not provided"); - panic e; + Filter[] newFilters = authFilters; + // add existing filters next + int i = 0; + while (i < config.filters.length()) { + newFilters[i + (newFilters.length())] = config.filters[i]; + i = i + 1; + } + config.filters = newFilters; } - } else { - error e = error("Unsupported auth scheme"); - panic e; } + // No need to validate else part since the function is called if and only if the `auth is ListenerAuth` } ////////////////////////////////// diff --git a/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/AuthnHandlerChainTest.java b/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/AuthnHandlerChainTest.java deleted file mode 100644 index 7591c4f3356c..000000000000 --- a/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/AuthnHandlerChainTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.ballerinalang.stdlib.auth; - -import org.ballerinalang.config.ConfigRegistry; -import org.ballerinalang.launcher.util.BCompileUtil; -import org.ballerinalang.launcher.util.BRunUtil; -import org.ballerinalang.launcher.util.CompileResult; -import org.ballerinalang.model.values.BBoolean; -import org.ballerinalang.model.values.BMap; -import org.ballerinalang.model.values.BValue; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collections; - -/** - * Authentication handler chain Testcase. - */ -public class AuthnHandlerChainTest { - - private static final String BALLERINA_CONF = "ballerina.conf"; - private CompileResult compileResult; - private Path secretCopyPath; - - @BeforeClass - public void setup() throws IOException { - String resourceRoot = Paths.get("src", "test", "resources").toAbsolutePath().toString(); - Path sourceRoot = Paths.get(resourceRoot, "test-src", "auth"); - Path ballerinaConfPath = Paths.get(resourceRoot, "datafiles", "config", "authprovider", BALLERINA_CONF); - - // Copy the ballerina.conf to the source root before starting the tests - compileResult = BCompileUtil.compile(sourceRoot.resolve("authn-handler-chain-test.bal").toString()); - - String secretFile = "secret.txt"; - Path secretFilePath = Paths.get(resourceRoot, "datafiles", "config", secretFile); - secretCopyPath = Paths.get(resourceRoot, "datafiles", "config", "authprovider", secretFile); - Files.deleteIfExists(secretCopyPath); - copySecretFile(secretFilePath.toString(), secretCopyPath.toString()); - - // load configs - ConfigRegistry registry = ConfigRegistry.getInstance(); - registry.initRegistry(Collections.singletonMap("b7a.config.secret", secretCopyPath.toString()), - ballerinaConfPath.toString(), null); - } - - private void copySecretFile(String from, String to) throws IOException { - Files.copy(Paths.get(from), Paths.get(to)); - } - - @Test(description = "Test case for creating authn handler chain") - public void testCreateAuthnHandlerChain() { - BValue[] returns = BRunUtil.invoke(compileResult, "testCreateAuthnHandlerChain"); - Assert.assertTrue(returns[0] instanceof BMap); - Assert.assertNotNull(returns[0]); - } - - @Test(description = "Test case for authn handler chain authn failure scenario") - public void testAuthFailure() { - BValue[] returns = BRunUtil.invoke(compileResult, "testAuthFailure"); - Assert.assertTrue(returns[0] instanceof BBoolean); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); - } - - @Test(description = "Test case for authn handler chain authn failure scenario with specific handlers") - public void testAuthFailureWithSpecificHandlers() { - BValue[] returns = BRunUtil.invoke(compileResult, "testAuthFailureWithSpecificHandlers"); - Assert.assertTrue(returns[0] instanceof BBoolean); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); - } - - @Test(description = "Test case for authn handler chain authn success scenario") - public void testAuthSuccessWithSpecificHandlers() { - BValue[] returns = BRunUtil.invoke(compileResult, "testAuthSuccessWithSpecificHandlers"); - Assert.assertTrue(returns[0] instanceof BBoolean); - Assert.assertTrue(((BBoolean) returns[0]).booleanValue()); - } - - @Test(description = "Test case for authn handler chain authn success scenario with specific handlers") - public void testAuthSuccess() { - BValue[] returns = BRunUtil.invoke(compileResult, "testAuthSuccess"); - Assert.assertTrue(returns[0] instanceof BBoolean); - Assert.assertTrue(((BBoolean) returns[0]).booleanValue()); - } - - @AfterClass - public void tearDown() throws IOException { - Files.deleteIfExists(secretCopyPath); - } -} diff --git a/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/AuthnHandlerTest.java b/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/BasicAuthnHandlerTest.java similarity index 91% rename from stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/AuthnHandlerTest.java rename to stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/BasicAuthnHandlerTest.java index 8ca3a378c708..0459d9904150 100644 --- a/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/AuthnHandlerTest.java +++ b/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/BasicAuthnHandlerTest.java @@ -23,6 +23,7 @@ import org.ballerinalang.launcher.util.BRunUtil; import org.ballerinalang.launcher.util.CompileResult; import org.ballerinalang.model.values.BBoolean; +import org.ballerinalang.model.values.BString; import org.ballerinalang.model.values.BValue; import org.testng.Assert; import org.testng.annotations.AfterClass; @@ -38,7 +39,7 @@ /** * Authentication handler testcase. */ -public class AuthnHandlerTest { +public class BasicAuthnHandlerTest { private static final String BALLERINA_CONF = "ballerina.conf"; private CompileResult compileResult; @@ -51,7 +52,7 @@ public void setup() throws IOException { Path ballerinaConfPath = Paths.get(resourceRoot, "datafiles", "config", "authprovider", BALLERINA_CONF); // Copy the ballerina.conf to the source root before starting the tests - compileResult = BCompileUtil.compile(sourceRoot.resolve("authn-handler-test.bal").toString()); + compileResult = BCompileUtil.compile(sourceRoot.resolve("basic-authn-handler-test.bal").toString()); String secretFile = "secret.txt"; Path secretFilePath = Paths.get(resourceRoot, "datafiles", "config", secretFile); @@ -97,17 +98,10 @@ public void testHandleHttpBasicAuth() { Assert.assertTrue(((BBoolean) returns[0]).booleanValue()); } - @Test(description = "Test case for extracting non existing basic auth header value") - public void testNonExistingBasicAuthHeaderValue() { - BValue[] returns = BRunUtil.invoke(compileResult, "testNonExistingBasicAuthHeaderValue"); - Assert.assertNotNull(returns); - Assert.assertNull(returns[0]); - } - @Test(description = "Test case for extracting basic auth header value") public void testExtractBasicAuthHeaderValue() { BValue[] returns = BRunUtil.invoke(compileResult, "testExtractBasicAuthHeaderValue"); - Assert.assertNotNull(returns); + Assert.assertTrue(returns[0] instanceof BString); // no error should be returned Assert.assertEquals(returns[0].stringValue(), "Basic aXN1cnU6eHh4"); } diff --git a/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/JWTAuthnHandlerTest.java b/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/JWTAuthnHandlerTest.java index ae2308c85472..dd0c549817a7 100644 --- a/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/JWTAuthnHandlerTest.java +++ b/stdlib/http/src/test/java/org/ballerinalang/stdlib/auth/JWTAuthnHandlerTest.java @@ -23,6 +23,7 @@ import org.ballerinalang.launcher.util.BRunUtil; import org.ballerinalang.launcher.util.CompileResult; import org.ballerinalang.model.values.BBoolean; +import org.ballerinalang.model.values.BError; import org.ballerinalang.model.values.BInteger; import org.ballerinalang.model.values.BMap; import org.ballerinalang.model.values.BString; @@ -149,8 +150,7 @@ public void testCanHandleHttpJwtAuth() { @Test(description = "Test case for JWT auth interceptor authentication failure") public void testHandleHttpJwtAuthFailure() { BValue[] returns = BRunUtil.invoke(compileResult, "testHandleHttpJwtAuthFailure"); - Assert.assertTrue(returns[0] instanceof BBoolean); - Assert.assertFalse(((BBoolean) returns[0]).booleanValue()); + Assert.assertTrue(returns[0] instanceof BError); } @Test(description = "Test case for JWT auth interceptor authentication success") diff --git a/stdlib/http/src/test/resources/test-src/auth/authn-handler-chain-test.bal b/stdlib/http/src/test/resources/test-src/auth/authn-handler-chain-test.bal deleted file mode 100644 index 085a929f9f3e..000000000000 --- a/stdlib/http/src/test/resources/test-src/auth/authn-handler-chain-test.bal +++ /dev/null @@ -1,67 +0,0 @@ -import ballerina/auth; -import ballerina/http; - -function testCreateAuthnHandlerChain() returns (http:AuthnHandlerChain) { - http:AuthHandlerRegistry registry = new; - http:AuthnHandlerChain authnHandlerChain = new(registry); - return authnHandlerChain; -} - -function testAuthFailure() returns (boolean) { - http:AuthHandlerRegistry registry = new; - registry.add("basicProvider1", createBasicAuthnHandler()); - http:Request inRequest = createRequest(); - string basicAutheaderValue = "123Basic xxxxx"; - inRequest.setHeader("123Authorization", basicAutheaderValue); - http:AuthnHandlerChain authnHandlerChain = new(registry); - return authnHandlerChain.handle(inRequest); -} - -function testAuthFailureWithSpecificHandlers() returns (boolean) { - http:AuthHandlerRegistry registry = new; - registry.add("basicProvider1", createBasicAuthnHandler()); - http:Request inRequest = createRequest(); - string basicAutheaderValue = "123Basic xxxxx"; - inRequest.setHeader("123Authorization", basicAutheaderValue); - http:AuthnHandlerChain authnHandlerChain = new(registry); - string[] authProviders = []; - authProviders[0] = "basicProvider1"; - return authnHandlerChain.handleWithSpecificAuthnHandlers(authProviders, inRequest); -} - -function testAuthSuccess() returns (boolean) { - http:AuthHandlerRegistry registry = new; - registry.add("basicProvider1", createBasicAuthnHandler()); - http:Request inRequest = createRequest(); - string basicAutheaderValue = "Basic aXN1cnU6eHh4"; - inRequest.setHeader("Authorization", basicAutheaderValue); - http:AuthnHandlerChain authnHandlerChain = new(registry); - return authnHandlerChain.handle(inRequest); -} - -function testAuthSuccessWithSpecificHandlers() returns (boolean) { - http:AuthHandlerRegistry registry = new; - registry.add("basicProvider1", createBasicAuthnHandler()); - http:Request inRequest = createRequest(); - string basicAutheaderValue = "Basic aXN1cnU6eHh4"; - inRequest.setHeader("Authorization", basicAutheaderValue); - http:AuthnHandlerChain authnHandlerChain = new(registry); - string[] authProviders = []; - authProviders[0] = "basicProvider1"; - return authnHandlerChain.handleWithSpecificAuthnHandlers(authProviders, inRequest); -} - -function createRequest() returns (http:Request) { - http:Request inRequest = new; - inRequest.rawPath = "/helloWorld/sayHello"; - inRequest.method = "GET"; - inRequest.httpVersion = "1.1"; - return inRequest; -} - -function createBasicAuthnHandler() returns (http:HttpAuthnHandler) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - auth:AuthStoreProvider authStoreProvider = configAuthStoreProvider; - http:HttpBasicAuthnHandler basicAuthnHandler = new(authStoreProvider); - return basicAuthnHandler; -} diff --git a/stdlib/http/src/test/resources/test-src/auth/authn-handler-test.bal b/stdlib/http/src/test/resources/test-src/auth/authn-handler-test.bal deleted file mode 100644 index fded7d7fcf85..000000000000 --- a/stdlib/http/src/test/resources/test-src/auth/authn-handler-test.bal +++ /dev/null @@ -1,64 +0,0 @@ -import ballerina/auth; -import ballerina/http; - -function testCanHandleHttpBasicAuthWithoutHeader() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - auth:AuthStoreProvider authStoreProvider = configAuthStoreProvider; - http:HttpBasicAuthnHandler handler = new(authStoreProvider); - http:Request inRequest = createRequest(); - string basicAutheaderValue = "123Basic xxxxxx"; - inRequest.setHeader("123Authorization", basicAutheaderValue); - return handler.canHandle(inRequest); -} - -function testCanHandleHttpBasicAuth() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - auth:AuthStoreProvider authStoreProvider = configAuthStoreProvider; - http:HttpBasicAuthnHandler handler = new(authStoreProvider); - http:Request inRequest = createRequest(); - string basicAutheaderValue = "Basic xxxxxx"; - inRequest.setHeader("Authorization", basicAutheaderValue); - return handler.canHandle(inRequest); -} - -function testHandleHttpBasicAuthFailure() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - auth:AuthStoreProvider authStoreProvider = configAuthStoreProvider; - http:HttpBasicAuthnHandler handler = new(authStoreProvider); - http:Request inRequest = createRequest(); - string basicAutheaderValue = "Basic YW1pbGE6cHFy"; - inRequest.setHeader("Authorization", basicAutheaderValue); - return handler.handle(inRequest); -} - -function testHandleHttpBasicAuth() returns (boolean) { - auth:ConfigAuthStoreProvider configAuthStoreProvider = new({}); - auth:AuthStoreProvider authStoreProvider = configAuthStoreProvider; - http:HttpBasicAuthnHandler handler = new(authStoreProvider); - http:Request inRequest = createRequest(); - string basicAutheaderValue = "Basic aXN1cnU6eHh4"; - inRequest.setHeader("Authorization", basicAutheaderValue); - return handler.handle(inRequest); -} - -function testNonExistingBasicAuthHeaderValue() returns (string|()) { - // create dummy request - http:Request inRequest = createRequest(); - return http:extractBasicAuthHeaderValue(inRequest); -} - -function testExtractBasicAuthHeaderValue() returns (string|()) { - // create dummy request - http:Request inRequest = createRequest(); - string basicAutheaderValue = "Basic aXN1cnU6eHh4"; - inRequest.setHeader("Authorization", basicAutheaderValue); - return http:extractBasicAuthHeaderValue(inRequest); -} - -function createRequest() returns (http:Request) { - http:Request inRequest = new; - inRequest.rawPath = "/helloWorld/sayHello"; - inRequest.method = "GET"; - inRequest.httpVersion = "1.1"; - return inRequest; -} diff --git a/stdlib/http/src/test/resources/test-src/auth/basic-authn-handler-test.bal b/stdlib/http/src/test/resources/test-src/auth/basic-authn-handler-test.bal new file mode 100644 index 000000000000..ed6ea55d176f --- /dev/null +++ b/stdlib/http/src/test/resources/test-src/auth/basic-authn-handler-test.bal @@ -0,0 +1,70 @@ +// Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/auth; +import ballerina/http; + +function testCanHandleHttpBasicAuthWithoutHeader() returns boolean { + auth:ConfigAuthStoreProvider configAuthStoreProvider = new; + http:BasicAuthnHandler handler = new(configAuthStoreProvider); + http:Request inRequest = createRequest(); + string basicAuthHeaderValue = "123Basic xxxxxx"; + inRequest.setHeader("123Authorization", basicAuthHeaderValue); + return handler.canHandle(inRequest); +} + +function testCanHandleHttpBasicAuth() returns boolean { + auth:ConfigAuthStoreProvider configAuthStoreProvider = new; + http:BasicAuthnHandler handler = new(configAuthStoreProvider); + http:Request inRequest = createRequest(); + string basicAuthHeaderValue = "Basic xxxxxx"; + inRequest.setHeader("Authorization", basicAuthHeaderValue); + return handler.canHandle(inRequest); +} + +function testHandleHttpBasicAuthFailure() returns boolean|error { + auth:ConfigAuthStoreProvider configAuthStoreProvider = new; + http:BasicAuthnHandler handler = new(configAuthStoreProvider); + http:Request inRequest = createRequest(); + string basicAuthHeaderValue = "Basic YW1pbGE6cHFy"; + inRequest.setHeader("Authorization", basicAuthHeaderValue); + return handler.handle(inRequest); +} + +function testHandleHttpBasicAuth() returns boolean|error { + auth:ConfigAuthStoreProvider configAuthStoreProvider = new; + http:BasicAuthnHandler handler = new(configAuthStoreProvider); + http:Request inRequest = createRequest(); + string basicAuthHeaderValue = "Basic aXN1cnU6eHh4"; + inRequest.setHeader("Authorization", basicAuthHeaderValue); + return handler.handle(inRequest); +} + +function testExtractBasicAuthHeaderValue() returns string|error { + // create dummy request + http:Request inRequest = createRequest(); + string basicAuthHeaderValue = "Basic aXN1cnU6eHh4"; + inRequest.setHeader("Authorization", basicAuthHeaderValue); + return http:extractAuthorizationHeaderValue(inRequest); +} + +function createRequest() returns http:Request { + http:Request inRequest = new; + inRequest.rawPath = "/helloWorld/sayHello"; + inRequest.method = "GET"; + inRequest.httpVersion = "1.1"; + return inRequest; +} diff --git a/stdlib/http/src/test/resources/test-src/auth/jwt-authn-handler-test.bal b/stdlib/http/src/test/resources/test-src/auth/jwt-authn-handler-test.bal index be8786aa751f..5a597456f49f 100644 --- a/stdlib/http/src/test/resources/test-src/auth/jwt-authn-handler-test.bal +++ b/stdlib/http/src/test/resources/test-src/auth/jwt-authn-handler-test.bal @@ -1,40 +1,56 @@ +// Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + import ballerina/auth; import ballerina/http; import ballerina/crypto; -function testCanHandleHttpJwtAuthWithoutHeader() returns (boolean) { - http:HttpJwtAuthnHandler handler = new(createJwtAuthProvider("ballerina/security/ballerinaTruststore.p12")); +function testCanHandleHttpJwtAuthWithoutHeader() returns boolean { + http:JwtAuthnHandler handler = new(createJwtAuthProvider("ballerina/security/ballerinaTruststore.p12")); http:Request request = createRequest(); string authHeaderValue = "Basic xxxxxx"; request.setHeader("Authorization", authHeaderValue); return handler.canHandle(request); } -function testCanHandleHttpJwtAuth() returns (boolean) { - http:HttpJwtAuthnHandler handler = new(createJwtAuthProvider("ballerina/security/ballerinaTruststore.p12")); +function testCanHandleHttpJwtAuth() returns boolean { + http:JwtAuthnHandler handler = new(createJwtAuthProvider("ballerina/security/ballerinaTruststore.p12")); http:Request request = createRequest(); string authHeaderValue = "Bearer xxx.yyy.zzz"; request.setHeader("Authorization", authHeaderValue); return handler.canHandle(request); } -function testHandleHttpJwtAuthFailure() returns (boolean) { - http:HttpJwtAuthnHandler handler = new(createJwtAuthProvider("ballerina/security/ballerinaTruststore.p12")); +function testHandleHttpJwtAuthFailure() returns boolean|error { + http:JwtAuthnHandler handler = new(createJwtAuthProvider("ballerina/security/ballerinaTruststore.p12")); http:Request request = createRequest(); string authHeaderValue = "Bearer xxx.yyy.zzz"; request.setHeader("Authorization", authHeaderValue); return handler.handle(request); } -function testHandleHttpJwtAuth(string token, string trustStorePath) returns (boolean) { - http:HttpJwtAuthnHandler handler = new(createJwtAuthProvider(trustStorePath)); +function testHandleHttpJwtAuth(string token, string trustStorePath) returns boolean|error { + http:JwtAuthnHandler handler = new(createJwtAuthProvider(trustStorePath)); http:Request request = createRequest(); string authHeaderValue = "Bearer " + token; request.setHeader("Authorization", authHeaderValue); return handler.handle(request); } -function createRequest() returns (http:Request) { +function createRequest() returns http:Request { http:Request inRequest = new; inRequest.rawPath = "/helloWorld/sayHello"; inRequest.method = "GET"; diff --git a/stdlib/websub/src/main/ballerina/websub/hub_client.bal b/stdlib/websub/src/main/ballerina/websub/hub_client.bal index c65f225044b5..f6d2dc594477 100644 --- a/stdlib/websub/src/main/ballerina/websub/hub_client.bal +++ b/stdlib/websub/src/main/ballerina/websub/hub_client.bal @@ -323,8 +323,9 @@ function processHubResponse(@sensitive string hub, @sensitive string mode, # + auth - The auth config to use at the hub, if specified # + return - `SubscriptionChangeResponse` indicating subscription/unsubscription details, if the request was successful # else `error` if an error occurred -function invokeClientConnectorOnRedirection(@sensitive string hub, @sensitive string mode, SubscriptionChangeRequest - subscriptionChangeRequest, http:AuthConfig? auth, int remainingRedirects) +function invokeClientConnectorOnRedirection(@sensitive string hub, @sensitive string mode, + SubscriptionChangeRequest subscriptionChangeRequest, + http:OutboundAuthConfig? auth, int remainingRedirects) returns @tainted SubscriptionChangeResponse|error { if (mode == MODE_SUBSCRIBE) { @@ -333,8 +334,9 @@ function invokeClientConnectorOnRedirection(@sensitive string hub, @sensitive st return unsubscribeWithRetries(hub, subscriptionChangeRequest, auth, remainingRedirects = remainingRedirects); } -function subscribeWithRetries(string hubUrl, SubscriptionChangeRequest subscriptionRequest, http:AuthConfig? auth, - int remainingRedirects = 0) returns @tainted SubscriptionChangeResponse| error { +function subscribeWithRetries(string hubUrl, SubscriptionChangeRequest subscriptionRequest, + http:OutboundAuthConfig? auth, int remainingRedirects = 0) + returns @tainted SubscriptionChangeResponse| error { http:Client clientEndpoint = new http:Client(hubUrl, config = { auth: auth }); http:Request builtSubscriptionRequest = buildSubscriptionChangeRequest(MODE_SUBSCRIBE, subscriptionRequest); var response = clientEndpoint->post("", builtSubscriptionRequest); @@ -342,8 +344,9 @@ function subscribeWithRetries(string hubUrl, SubscriptionChangeRequest subscript remainingRedirects); } -function unsubscribeWithRetries(string hubUrl, SubscriptionChangeRequest unsubscriptionRequest, http:AuthConfig? auth, - int remainingRedirects = 0) returns @tainted SubscriptionChangeResponse|error { +function unsubscribeWithRetries(string hubUrl, SubscriptionChangeRequest unsubscriptionRequest, + http:OutboundAuthConfig? auth, int remainingRedirects = 0) + returns @tainted SubscriptionChangeResponse|error { http:Client clientEndpoint = new http:Client(hubUrl, config = { auth: auth }); diff --git a/stdlib/websub/src/main/ballerina/websub/hub_service.bal b/stdlib/websub/src/main/ballerina/websub/hub_service.bal index 72b44ab93c1f..4749b068308b 100644 --- a/stdlib/websub/src/main/ballerina/websub/hub_service.bal +++ b/stdlib/websub/src/main/ballerina/websub/hub_service.bal @@ -29,10 +29,8 @@ map pendingRequests = {}; service hubService = @http:ServiceConfig { basePath: BASE_PATH, - authConfig: { - authentication: { - enabled: config:getAsBoolean("b7a.websub.hub.auth.enabled", defaultValue = false) - }, + auth: { + enabled: config:getAsBoolean("b7a.websub.hub.auth.enabled", defaultValue = false), scopes: getArray(config:getAsString("b7a.websub.hub.auth.scopes")) } } @@ -550,12 +548,12 @@ function buildWebSubLinkHeader(string hub, string topic) returns (string) { # Construct an array of groups from the comma separed group string passed # -# + groupString - comma separated string of groups -# + return - array of groups, nil if the groups string is empty/nil -function getArray(string groupString) returns string[]? { +# + groupString - Comma separated string of groups +# + return - Array of groups +function getArray(string groupString) returns string[] { string[] groupsArr = []; if (groupString.length() == 0) { - return (); + return groupsArr; } return groupString.split(","); } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthBaseTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthBaseTest.java index 98b99f90f3b3..4fbecb247001 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthBaseTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthBaseTest.java @@ -20,6 +20,8 @@ import org.ballerinalang.test.BaseTest; import org.ballerinalang.test.context.BServerInstance; +import org.ballerinalang.test.util.HttpResponse; +import org.testng.Assert; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; @@ -32,12 +34,12 @@ public class AuthBaseTest extends BaseTest { protected static BServerInstance serverInstance; - protected static EmbeddedDirectoryServer embeddedDirectoryServer; + private static EmbeddedDirectoryServer embeddedDirectoryServer; @BeforeGroups(value = "auth-test", alwaysRun = true) public void start() throws Exception { int[] requiredPorts = new int[]{9090, 9091, 9092, 9093, 9094, 9095, 9096, 9097, 9098, 9099, 9100, 9101, 9102, - 9103, 9104, 9105, 9106, 9107, 9108, 9190, 9191, 9192, 9193, 9194, 9195, 9196}; + 9103, 9104, 9105, 9106, 9107, 9108, 9109, 9110, 9111, 9112, 9113, 9195, 9196}; embeddedDirectoryServer = new EmbeddedDirectoryServer(); embeddedDirectoryServer.startLdapServer(9389); @@ -55,4 +57,19 @@ public void cleanup() throws Exception { serverInstance.removeAllLeechers(); serverInstance.shutdownServer(); } + + void assertOK(HttpResponse response) { + Assert.assertNotNull(response); + Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + } + + void assertUnauthorized(HttpResponse response) { + Assert.assertNotNull(response); + Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + } + + void assertForbidden(HttpResponse response) { + Assert.assertNotNull(response); + Assert.assertEquals(response.getResponseCode(), 403, "Response code mismatched"); + } } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnConfigInheritanceAuthDisableTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnConfigInheritanceAuthDisableTest.java deleted file mode 100644 index d87e4c394ce3..000000000000 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnConfigInheritanceAuthDisableTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.ballerinalang.test.auth; - -import org.ballerinalang.test.context.Constant; -import org.ballerinalang.test.util.HttpResponse; -import org.ballerinalang.test.util.HttpsClientRequest; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.util.HashMap; -import java.util.Map; - -/** - * Test cases for disabling authorization scenarios. - * - * @since 0.970.0 - */ -@Test(groups = "auth-test") -public class AuthnConfigInheritanceAuthDisableTest extends AuthBaseTest { - - private final int servicePort = Constant.DEFAULT_HTTP_PORT; - - @Test(description = "non secured resource test case with no auth headers") - public void testResourceLevelAuthDisableWithNoAuthHeaders() throws Exception { - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), - serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); - } - - @Test(description = "non secured resource test case") - public void testResourceLevelAuthDisable() throws Exception { - Map headersMap = new HashMap<>(); - headersMap.put("Authorization", "Basic dGVzdDp0ZXN0MTIz"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), - headersMap, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); - } -} diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnConfigInheritanceTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnConfigInheritanceTest.java index a40f4b99a81d..284048126374 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnConfigInheritanceTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnConfigInheritanceTest.java @@ -20,37 +20,116 @@ import org.ballerinalang.test.util.HttpResponse; import org.ballerinalang.test.util.HttpsClientRequest; -import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; import java.util.Map; /** - * Test cases for authorization config inheritance scenarios. + * Test cases for authentication config inheritance scenarios. */ @Test(groups = "auth-test") public class AuthnConfigInheritanceTest extends AuthBaseTest { - private final int servicePort = 9091; + private final int servicePort = 9090; - @Test(description = "invalid scope test case") - public void testAuthzFailureWithInheritedConfigs() throws Exception { + @Test(description = "Secured resource, secured service test case with no auth headers") + public void testNoAuthHeaders1() throws Exception { + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo1/test1"), + serverInstance.getServerHome()); + assertUnauthorized(response); + } + + @Test(description = "Non secured resource, secured service test case with no auth headers") + public void testNoAuthHeaders2() throws Exception { + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo1/test2"), + serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Secured resource, non secured service test case with no auth headers") + public void testNoAuthHeaders3() throws Exception { + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo2/test1"), + serverInstance.getServerHome()); + assertUnauthorized(response); + } + + @Test(description = "Non secured resource, non secured service test case with no auth headers") + public void testNoAuthHeaders4() throws Exception { + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo2/test2"), + serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Secured resource, secured service test case with valid auth headers") + public void testValidAuthHeaders1() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo1/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Non secured resource, secured service test case with valid auth headers") + public void testValidAuthHeaders2() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo1/test2"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Secured resource, non secured service test case with valid auth headers") + public void testValidAuthHeaders3() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo2/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Non secured resource, non secured service test case with valid auth headers") + public void testValidAuthHeaders4() throws Exception { Map headersMap = new HashMap<>(); headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo2/test2"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Secured resource, secured service test case with invalid auth headers") + public void testInvalidAuthHeaders1() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic dGVzdDp0ZXN0MTIz"); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo1/test1"), + headersMap, serverInstance.getServerHome()); + assertUnauthorized(response); + } + + @Test(description = "Non secured resource, secured service test case with invalid auth headers") + public void testInvalidAuthHeaders2() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic dGVzdDp0ZXN0MTIz"); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo1/test2"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Secured resource, non secured service test case with invalid auth headers") + public void testInvalidAuthHeaders3() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic dGVzdDp0ZXN0MTIz"); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo2/test1"), headersMap, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 403, "Response code mismatched"); + assertUnauthorized(response); } - @Test(description = "Authn and authz failure test case") - public void testAuthFailureWithInheritedConfigs() throws Exception { + @Test(description = "Non secured resource, non secured service test case with invalid auth headers") + public void testInvalidAuthHeaders4() throws Exception { Map headersMap = new HashMap<>(); headersMap.put("Authorization", "Basic dGVzdDp0ZXN0MTIz"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo2/test2"), headersMap, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + assertOK(response); } } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithCustomHandlersTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithCustomHandlersTest.java new file mode 100644 index 000000000000..4321758d26f3 --- /dev/null +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithCustomHandlersTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ballerinalang.test.auth; + +import org.ballerinalang.test.util.HttpResponse; +import org.ballerinalang.test.util.HttpsClientRequest; +import org.testng.annotations.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * Test cases for authentication with custom handlers. + */ +@Test(groups = "auth-test") +public class AuthnWithCustomHandlersTest extends AuthBaseTest { + + private final int servicePort = 9113; + + @Test(description = "Secured resource, secured service test case with valid auth headers") + public void testNoAuthHeaders() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic YWJjOjEyMw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), + headersMap, serverInstance.getServerHome()); + assertUnauthorized(response); + } + + public void testInvalidAuthHeaders() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic YWJjOjEyMw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), + headersMap, serverInstance.getServerHome()); + assertUnauthorized(response); + } + + public void testValidAuthHeaders() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Custom YWJjOjEyMw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } +} diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithMultipleProvidersTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithMultipleHandlersTest.java similarity index 89% rename from tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithMultipleProvidersTest.java rename to tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithMultipleHandlersTest.java index f43bf8413157..e186613f9d70 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithMultipleProvidersTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithMultipleHandlersTest.java @@ -22,7 +22,6 @@ import org.ballerinalang.test.util.HttpResponse; import org.ballerinalang.test.util.HttpsClientRequest; import org.ballerinalang.test.util.TestConstant; -import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; @@ -34,9 +33,9 @@ * @since 0.983.0 */ @Test(groups = "auth-test") -public class AuthnWithMultipleProvidersTest extends AuthBaseTest { +public class AuthnWithMultipleHandlersTest extends AuthBaseTest { - private final int servicePort = 9099; + private final int servicePort = 9097; @Test(description = "Authn success test case with example1 issuer") public void testAuthSuccessWithExample1Issuer() throws Exception { @@ -64,10 +63,9 @@ public void testAuthSuccessWithExample1Issuer() throws Exception { "PiSX1FR-nIUTcJ9anaoQVEKo3OpkIPzd_4_95CpHXF1MaW18ww5h_NShQnUrN7myrBfc-UbHsqC1YEBAM2M-3NMs8jjgcZHfZ1J" + "jomZCjd5eUXz8R5Vl46uAlSbFAmxAfY1T-31qUB93eCL2iJfDc70OK2txohryntw9h-OePwQULJN0EiwpoI60HQFFlgC1g_crPI" + "DakBTiEITrbO3OzrNeCQFBN-Ji4BTXq97TulCIRNneDLCUBSRE1A"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo8/test8"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + assertOK(response); } @Test(description = "Authn success test case with example2 issuer") @@ -96,10 +94,9 @@ public void testAuthSuccessWithExample2Issuer() throws Exception { "m8qovBmVzzd7vDdgvpvRuNhmFmcv63Jc9KjyoBiA_BDjFy9oTTzP35-PRuekQ0xy3gGjcgqhPcQtmLOyeTUbMhcrpGLB-fYp4x" + "9OqRo5ZNtMrm0aOuMj-VbKACc2vBdju5gu_nEtxBGeFWVHd_9l7OqNUTibmFzEV34GXP8rvVl73JZnp5tJesH-GXArsCjvSj1Q" + "pvcLBUiAaXFeXPb9t4iHFugJzHY68eQQZcxyIxWVyj2eNV4HmBjvqVLQuA"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo8/test8"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + assertOK(response); } @Test(description = "Authn fail test case with example3 issuer") @@ -128,10 +125,9 @@ public void testAuthFailWithExample3Issuer() throws Exception { "yph3T7JzHGEXGCEXDmACywj58pnVKISsSb5tR8pDaidh-XRrCwE2hXB4X2_3fi9-Mn2U3ZFVb2q8-W9V9bmI1KJK-ALdKFuYu" + "Z9BzIq3YfZNyqAyFaQo9TFYhqNRvDbBsfdmjAfcj_SlYfSmbmTMG2FCahr9Tq_S3pMbh3S_6ii1-OqTGUukFdz1c08F5SvIZ9" + "t1xdW40dCnDrSR6urqVGys0Zg_Ru0mnPg4dU2JPuwDLuKzj4KzWXShZ2Il5Ol-IA"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo8/test8"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + assertUnauthorized(response); } @Test(description = "Authn fail test case with example1 issuer and invalid audience") @@ -158,9 +154,8 @@ public void testAuthFailWithExample1IssuerAndInvalidAudience() throws Exception "BAF35RJVepnoCq5ctdrgzcpYI3B8MSa07Sn00oEpSelzRK3SHPEglzGzOaG2GDWN2N2-TGF2IVSH1Bn3ovjFXsirh_uJZ9kbn" + "QhqrnZ2NIIjKaRa8y9RKtvwq3XnEvej2Ki7ddnx5AGSPXkiJ5AZBNtA5sRwEvJiffsff9tmJvI909Atf66WVylaFyP4e6E_Us" + "roxJPVxncPTRuewApF-RpXPKdheVEqQ4w"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo8/test8"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + assertUnauthorized(response); } } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithoutHTTPAnnotationsTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithoutHTTPAnnotationsTest.java index 016c59836c5d..2b1ecffc96ad 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithoutHTTPAnnotationsTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthnWithoutHTTPAnnotationsTest.java @@ -22,7 +22,6 @@ import org.ballerinalang.test.util.HttpResponse; import org.ballerinalang.test.util.HttpsClientRequest; import org.ballerinalang.test.util.TestConstant; -import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; @@ -37,17 +36,16 @@ @Test(groups = "auth-test") public class AuthnWithoutHTTPAnnotationsTest extends AuthBaseTest { - private final int servicePort = 9098; + private final int servicePort = 9096; @Test(description = "Authn and authz success test case") public void testAuthSuccess() throws Exception { Map headers = new HashMap<>(); headers.put(HttpHeaderNames.CONTENT_TYPE.toString(), TestConstant.CONTENT_TYPE_TEXT_PLAIN); headers.put("Authorization", "Basic aXN1cnU6eHh4"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo7/test7"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + assertOK(response); } @Test(description = "Authn failure test case") @@ -55,9 +53,8 @@ public void testAuthnFailure() throws Exception { Map headers = new HashMap<>(); headers.put(HttpHeaderNames.CONTENT_TYPE.toString(), TestConstant.CONTENT_TYPE_TEXT_PLAIN); headers.put("Authorization", "Basic aW52YWxpZFVzZXI6YWJj"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo7/test7"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + assertUnauthorized(response); } } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthzCacheTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthzCacheTest.java index 941ccc28ba0e..89d3a7e24903 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthzCacheTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthzCacheTest.java @@ -22,7 +22,6 @@ import org.ballerinalang.test.util.HttpResponse; import org.ballerinalang.test.util.HttpsClientRequest; import org.ballerinalang.test.util.TestConstant; -import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; @@ -36,7 +35,7 @@ @Test(groups = "auth-test") public class AuthzCacheTest extends AuthBaseTest { - private final int servicePort = 9100; + private final int servicePort = 9098; @Test(description = "Authn success test case with example1 issuer") public void testAuthCache() throws Exception { @@ -64,10 +63,9 @@ public void testAuthCache() throws Exception { "l2aawDBFag_4GJhRd__AxjZemCqAdKs-cqX-JNSWnB8m7cBfA9LOH-y2dmowNqv4VeMuuxKriMe9w-7YpnRPJrs-HIxLMgOdJa" + "YsFHEPL1wWDvlpt53wDjCveYw4OgD39S5g-pcemGUflVUMoKB3nti1qjzcIb6nDKdqQiAbnSN2UKEVLXQpZX5WUKe5SuFlKnS9" + "z1BbKC2z79eMe15yx8asas3krgJyKVNISUWlgPWvKHxyfh_RoQYgWPn-rhng1_P8Ag"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo9/test9"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + assertOK(response); // JWT used in the second request: // { @@ -93,10 +91,9 @@ public void testAuthCache() throws Exception { "XichRv_y7_VuY-WTm7QBtR5tqpBVAI59SezTE9NqxCIy-ol4RE7rQ7plOr2y80NNQfoWE6PCwsjFNc2v_FdXzR6ADvsnNZbRu" + "Z2nhnTpkDkdmgDOyonw4YZPG275ZQCRTJEjyUKnF4yEm9c2cwCtbOVzdThtzuJEmEcrRHAre7zZX857R2ZKo84TZ8Tes3maGY" + "dpwoUnOy9aseNB8iy0AAPQwf1MkpbgCUJFGLAWHAQsUBJXPpCPGMKVJ5CYzFiPC_bX_pUrzrXOJw"); - response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo9/test9"), + response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 403, "Response code mismatched"); + assertForbidden(response); // JWT used in the third request: // { @@ -122,9 +119,8 @@ public void testAuthCache() throws Exception { "eO9Kt3EIJHU4njheptz7Qfep_sEyYdq3CvQI5bKxUZw4bA-87AxTv_tFpSAbiBpGhD0rmhYAfkXF7QsWplDts_xFRhMmxHEsel" + "RKMg4F9-iX3HQYouJoRzyDJTETyzxC2vFE0FaCxVDrrs5B2KU3YB-etkPUWDFgzaoV13SaHxPBhj-f5arlfRaDk2XtbNnchHgs" + "LbLux8FaxyAglgRoDNgBgaCynbhUYAUnpr2JSx72FN8J0CJB5f31EMmmd4FukTtv-8w"); - response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo9/test9"), + response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + assertUnauthorized(response); } } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthzConfigInheritanceTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthzConfigInheritanceTest.java index 83bcc60ada3d..82c0ff2d22f6 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthzConfigInheritanceTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/AuthzConfigInheritanceTest.java @@ -20,7 +20,6 @@ import org.ballerinalang.test.util.HttpResponse; import org.ballerinalang.test.util.HttpsClientRequest; -import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; @@ -32,35 +31,250 @@ @Test(groups = "auth-test") public class AuthzConfigInheritanceTest extends AuthBaseTest { - private final int servicePort = 9092; - - @Test(description = "Authn and authz success test case") - public void testAuthSuccessWithInheritedAuthzConfigs() throws Exception { - Map headers = new HashMap<>(); - headers.put("Authorization", "Basic aXN1cnU6eHh4"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance - .getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); - } - - @Test(description = "Authn success and authz failure test case") - public void testAuthzFailureWithInheritedAuthzConfigs() throws Exception { - Map headers = new HashMap<>(); - headers.put("Authorization", "Basic aXNoYXJhOmFiYw=="); - HttpResponse response = HttpsClientRequest.doGet(serverInstance - .getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 403, "Response code mismatched"); - } - - @Test(description = "Authn and authz failure test case") - public void testAuthFailureWithInheritedAuthzConfigs() throws Exception { - Map headers = new HashMap<>(); - headers.put("Authorization", "Basic dGVzdDp0ZXN0MTIz"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance - .getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + private final int servicePort1 = 9091; + private final int servicePort2 = 9092; + private final int servicePort3 = 9093; + + @Test(description = "Listener - valid scopes, service - valid scopes and resource - valid scopes") + public void testValidScopesAtListener1() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort1, "echo1/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - valid scopes, service - valid scopes and resource - invalid scopes") + public void testValidScopesAtListener2() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort1, "echo1/test2"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - valid scopes, service - valid scopes and resource - scopes not given") + public void testValidScopesAtListener3() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort1, "echo1/test3"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - valid scopes, service - invalid scopes and resource - valid scopes") + public void testValidScopesAtListener4() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort1, "echo2/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - valid scopes, service - invalid scopes and resource - invalid scopes") + public void testValidScopesAtListener5() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort1, "echo2/test2"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - valid scopes, service - invalid scopes and resource - scopes not given") + public void testValidScopesAtListener6() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort1, "echo2/test3"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - valid scopes, service - scopes not given and resource - valid scopes") + public void testValidScopesAtListener7() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort1, "echo3/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - valid scopes, service - scopes not given and resource - invalid scopes") + public void testValidScopesAtListener8() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort1, "echo3/test2"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - valid scopes, service - scopes not given and resource - scopes not given") + public void testValidScopesAtListener9() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort1, "echo3/test3"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - invalid scopes, service - valid scopes and resource - valid scopes") + public void testInValidScopesAtListener1() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort2, "echo1/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - invalid scopes, service - valid scopes and resource - invalid scopes") + public void testInValidScopesAtListener2() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort2, "echo1/test2"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - invalid scopes, service - valid scopes and resource - scopes not given") + public void testInValidScopesAtListener3() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort2, "echo1/test3"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - invalid scopes, service - invalid scopes and resource - valid scopes") + public void testInValidScopesAtListener4() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort2, "echo2/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - invalid scopes, service - invalid scopes and resource - invalid scopes") + public void testInValidScopesAtListener5() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort2, "echo2/test2"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - invalid scopes, service - invalid scopes and resource - scopes not given") + public void testInValidScopesAtListener6() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort2, "echo2/test3"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - invalid scopes, service - scopes not given and resource - valid scopes") + public void testInValidScopesAtListener7() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort2, "echo3/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - invalid scopes, service - scopes not given and resource - invalid scopes") + public void testInValidScopesAtListener8() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort2, "echo3/test2"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - invalid scopes, service - scopes not given and resource - scopes not given") + public void testInValidScopesAtListener9() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort2, "echo3/test3"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - scopes not given, service - valid scopes and resource - valid scopes") + public void testNotGivenScopesAtListener1() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort3, "echo1/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - scopes not given, service - valid scopes and resource - invalid scopes") + public void testNotGivenScopesAtListener2() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort3, "echo1/test2"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - scopes not given, service - valid scopes and resource - scopes not given") + public void testNotGivenScopesAtListener3() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort3, "echo1/test3"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - scopes not given, service - invalid scopes and resource - valid scopes") + public void testNotGivenScopesAtListener4() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort3, "echo2/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - scopes not given, service - invalid scopes and resource - invalid scopes") + public void testNotGivenScopesAtListener5() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort3, "echo2/test2"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - scopes not given, service - invalid scopes and resource - scopes not given") + public void testNotGivenScopesAtListener6() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort3, "echo2/test3"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - scopes not given, service - scopes not given and resource - valid scopes") + public void testNotGivenScopesAtListener7() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort3, "echo3/test1"), + headersMap, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Listener - scopes not given, service - scopes not given and resource - invalid scopes") + public void testNotGivenScopesAtListener8() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort3, "echo3/test2"), + headersMap, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Listener - scopes not given, service - scopes not given and resource - scopes not given") + public void testNotGivenScopesAtListener9() throws Exception { + Map headersMap = new HashMap<>(); + headersMap.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort3, "echo3/test3"), + headersMap, serverInstance.getServerHome()); + assertOK(response); } } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/EmbeddedDirectoryServer.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/EmbeddedDirectoryServer.java index c830e500415a..ef8024aeac45 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/EmbeddedDirectoryServer.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/EmbeddedDirectoryServer.java @@ -67,7 +67,7 @@ public class EmbeddedDirectoryServer { * * @param partitionId The partition Id * @param partitionDn The partition DN - * @param dnFactory The factory for DNs + * @param dnFactory The factory for DNs * @return The newly added partition * @throws Exception If the partition can't be added */ @@ -109,7 +109,7 @@ public void startLdapServer(int port) throws Exception { // Create a new partition named 'b7a'. Partition b7aPartition = addPartition(LDAP_AUTH_TEST_PARTITION_NAME, - LDAP_AUTH_TEST_PARTITION_DN, service.getDnFactory()); + LDAP_AUTH_TEST_PARTITION_DN, service.getDnFactory()); service.addPartition(b7aPartition); // Start the service @@ -119,7 +119,7 @@ public void startLdapServer(int port) throws Exception { // Load the LDIF file String ldif = new File("src" + File.separator + "test" + File.separator + "resources" + File.separator + - "auth" + File.separator + "ldif").getAbsolutePath() + File.separator + "users-import.ldif"; + "auth" + File.separator + "ldif").getAbsolutePath() + File.separator + "users-import.ldif"; LdifFileLoader ldifLoader = new LdifFileLoader(service.getAdminSession(), ldif); ldifLoader.execute(); @@ -166,7 +166,7 @@ private void initSystemPartition() throws LdapInvalidDnException { /** * Stops directory apache directory service. */ - public void stopLdapService() { + void stopLdapService() { ldapServer.stop(); workDir.delete(); } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/LdapAuthStoreTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/LdapAuthStoreTest.java index 101316cda2f4..0d99b0d330b2 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/LdapAuthStoreTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/LdapAuthStoreTest.java @@ -20,7 +20,6 @@ import org.ballerinalang.test.util.HttpResponse; import org.ballerinalang.test.util.HttpsClientRequest; -import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; @@ -34,8 +33,8 @@ @Test(groups = "auth-test") public class LdapAuthStoreTest extends AuthBaseTest { - private final int servicePort = 9096; - private final int authzServicePort = 9097; + private final int servicePort = 9111; + private final int authzServicePort = 9112; @Test(description = "Test authenticate and authorize request against ldap auth store") public void testAuthenticationWithInvalidCredentials() throws Exception { @@ -43,7 +42,7 @@ public void testAuthenticationWithInvalidCredentials() throws Exception { headersMap.put("Authorization", "Basic dmlqaXRoYTp2aWppdGhhQDEyMw=="); HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "ldapAuth/disableAuthz"), headersMap, serverInstance.getServerHome()); - assertResponse(response, 401, "Authentication failure"); + assertUnauthorized(response); } @Test(description = "Test authenticate request against ldap auth store") @@ -52,7 +51,7 @@ public void testAuthenticationWithLDAPAuthstoreWithoutAuthorization() throws Exc headersMap.put("Authorization", "Basic dmlqaXRoYTpiYWxsZXJpbmE="); HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "ldapAuth/disableAuthz"), headersMap, serverInstance.getServerHome()); - assertResponse(response, 200, "Hello, World!!!"); + assertOK(response); } @Test(description = "Test authenticate and authorize request against ldap auth store") @@ -61,21 +60,15 @@ public void testAuthenticationWithLDAPAuthstoreWithAuthorization() throws Except headersMap.put("Authorization", "Basic dmlqaXRoYTpiYWxsZXJpbmE="); HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "ldapAuth/enableAuthz"), headersMap, serverInstance.getServerHome()); - assertResponse(response, 200, "Hello, World!!!"); + assertOK(response); } @Test(description = "Test the failure of authorization request against ldap auth store") - public void testAuthorizatioFailureWithLDAPAuthstore() throws Exception { + public void testAuthorizationFailureWithLDAPAuthStore() throws Exception { Map headersMap = new HashMap<>(); headersMap.put("Authorization", "Basic dmlqaXRoYTpiYWxsZXJpbmE="); HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(authzServicePort, "auth/failAuthz"), headersMap, serverInstance.getServerHome()); - assertResponse(response, 403, "Authorization failure"); - } - - private void assertResponse(HttpResponse response, int statusCode, String message) { - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), statusCode, "Response code mismatched"); - Assert.assertEquals(response.getData(), message, "Response message content mismatched."); + assertForbidden(response); } } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/ResourceLevelAuthTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/ResourceLevelAuthTest.java index 0dd0e90fbc77..2e5205f7eae0 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/ResourceLevelAuthTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/ResourceLevelAuthTest.java @@ -20,7 +20,6 @@ import org.ballerinalang.test.util.HttpResponse; import org.ballerinalang.test.util.HttpsClientRequest; -import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; @@ -32,7 +31,7 @@ @Test(groups = "auth-test") public class ResourceLevelAuthTest extends AuthBaseTest { - private final int servicePort = 9093; + private final int servicePort = 9094; @Test(description = "Authn and authz success test case") public void testAuthSuccessWithResourceLevelConfigs() throws Exception { @@ -40,8 +39,7 @@ public void testAuthSuccessWithResourceLevelConfigs() throws Exception { headers.put("Authorization", "Basic aXN1cnU6eHh4"); HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + assertOK(response); } @Test(description = "Authn success and authz failure test case") @@ -50,8 +48,7 @@ public void testAuthzFailureWithResourceLevelConfigs() throws Exception { headers.put("Authorization", "Basic aXNoYXJhOmFiYw=="); HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 403, "Response code mismatched"); + assertForbidden(response); } @Test(description = "Authn and authz failure test case") @@ -60,7 +57,6 @@ public void testAuthFailureWithResourceLevelConfigs() throws Exception { headers.put("Authorization", "Basic dGVzdDp0ZXN0MTIz"); HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + assertUnauthorized(response); } } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/SecureClientWrongAuthProviderTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/SecureClientWrongAuthProviderTest.java deleted file mode 100644 index 4be28764b5ab..000000000000 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/SecureClientWrongAuthProviderTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.ballerinalang.test.auth; - -import io.netty.handler.codec.http.HttpHeaderNames; -import org.ballerinalang.test.util.HttpResponse; -import org.ballerinalang.test.util.HttpsClientRequest; -import org.ballerinalang.test.util.TestConstant; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.util.HashMap; -import java.util.Map; - -/** - * Test cases for verifying wrong auth provider for a service. - */ -@Test(groups = "auth-test") -public class SecureClientWrongAuthProviderTest extends AuthBaseTest { - - @Test(description = "Authn failure with wrong auth provider") - public void testAuthSuccess() throws Exception { - Map headers = new HashMap<>(); - headers.put(HttpHeaderNames.CONTENT_TYPE.toString(), TestConstant.CONTENT_TYPE_TEXT_PLAIN); - headers.put("Authorization", "Basic aXN1cnU6eHh4"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9194, "echo/test"), headers, - serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); - } -} diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/ServiceLevelAuthnTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/ServiceLevelAuthnTest.java index 705e24501d49..c5fd338b19f3 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/ServiceLevelAuthnTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/ServiceLevelAuthnTest.java @@ -20,7 +20,6 @@ import org.ballerinalang.test.util.HttpResponse; import org.ballerinalang.test.util.HttpsClientRequest; -import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; @@ -32,9 +31,36 @@ @Test(groups = "auth-test") public class ServiceLevelAuthnTest extends AuthBaseTest { - private final int servicePort = 9094; - private final int servicePortForExpiredCertificateTest = 9101; - private final int servicePortForExpiredCertificateTestWithNoExpiryValidation = 9102; + private final int servicePort = 9095; + private final int servicePortForExpiredCertificateTest = 9099; + private final int servicePortForExpiredCertificateTestWithNoExpiryValidation = 9100; + + @Test(description = "Authn and authz success test case") + public void testAuthSuccessWithServiceLevelConfigs() throws Exception { + Map headers = new HashMap<>(); + headers.put("Authorization", "Basic aXN1cnU6eHh4"); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), + headers, serverInstance.getServerHome()); + assertOK(response); + } + + @Test(description = "Authn success and authz failure test case") + public void testAuthzFailureWithServiceLevelConfigs() throws Exception { + Map headers = new HashMap<>(); + headers.put("Authorization", "Basic aXNoYXJhOmFiYw=="); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), + headers, serverInstance.getServerHome()); + assertForbidden(response); + } + + @Test(description = "Authn and authz failure test case") + public void testAuthFailureWithServiceLevelConfigs() throws Exception { + Map headers = new HashMap<>(); + headers.put("Authorization", "Basic dGVzdDp0ZXN0MTIz"); + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(servicePort, "echo/test"), + headers, serverInstance.getServerHome()); + assertUnauthorized(response); + } @Test(description = "Auth with JWT signed with expired trusted certificate") public void testAuthnWithJWTSignedWithExpiredTrustedCertificate() throws Exception { @@ -61,10 +87,9 @@ public void testAuthnWithJWTSignedWithExpiredTrustedCertificate() throws Excepti "18xqUzweCRL-DLAAYwjbzGQ56ekbEdAg02sFco4aozOyt8OUDwS9cH_JlhUn2JEHmVKaatljEnfgRc8fOW6Y5IJ7dOPp7ra5e" + "00sk7JwYY8wKaZWxAGSgRpWgTY6C4XRjGIsR5ZWQdXCAnV27idGDrtR2uG4YQwCWUCzA"); HttpResponse response = HttpsClientRequest.doGet(serverInstance - .getServiceURLHttps(servicePortForExpiredCertificateTest, "echo13/test13"), + .getServiceURLHttps(servicePortForExpiredCertificateTest, "echo/test"), headersMap, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + assertUnauthorized(response); } @Test(description = "Auth with JWT signed with expired trusted certificate but with expiry validation off") @@ -92,9 +117,8 @@ public void testAuthnWithJWTSignedWithExpiredTrustedCertificateWithNoExpiryValid "18xqUzweCRL-DLAAYwjbzGQ56ekbEdAg02sFco4aozOyt8OUDwS9cH_JlhUn2JEHmVKaatljEnfgRc8fOW6Y5IJ7dOPp7ra5e" + "00sk7JwYY8wKaZWxAGSgRpWgTY6C4XRjGIsR5ZWQdXCAnV27idGDrtR2uG4YQwCWUCzA"); HttpResponse response = HttpsClientRequest.doGet(serverInstance - .getServiceURLHttps(servicePortForExpiredCertificateTestWithNoExpiryValidation, - "echo14/test14"), headersMap, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + .getServiceURLHttps(servicePortForExpiredCertificateTestWithNoExpiryValidation, + "echo/test"), headersMap, serverInstance.getServerHome()); + assertOK(response); } } diff --git a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/TokenPropagationTest.java b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/TokenPropagationTest.java index 47031054df05..dabedecf2c52 100644 --- a/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/TokenPropagationTest.java +++ b/tests/ballerina-integration-test/src/test/java/org/ballerinalang/test/auth/TokenPropagationTest.java @@ -20,7 +20,6 @@ import org.ballerinalang.test.util.HttpResponse; import org.ballerinalang.test.util.HttpsClientRequest; -import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; @@ -36,20 +35,18 @@ public class TokenPropagationTest extends AuthBaseTest { public void testTokenPropagationWithBasicAuthInbound() throws Exception { Map headers = new HashMap<>(); headers.put("Authorization", "Basic aXN1cnU6eHh4"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9192, "passthrough"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9103, "passthrough"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + assertOK(response); } @Test(description = "Test behaviour when JWT Token propagation is disabled, resulting in authn failure") public void testWithoutTokenPropagation() throws Exception { Map headers = new HashMap<>(); headers.put("Authorization", "Basic aXN1cnU6eHh4"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9190, "passthrough"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9101, "passthrough"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + assertUnauthorized(response); } @Test(description = "Test JWT Token propagation with JWT auth as the inbound authentication mechanism, without " + @@ -63,10 +60,10 @@ public void testTokenPropagationWithJwtAuthInbound() throws Exception { "ksSeIT9McZxjPiSX1FR-nIUTcJ9anaoQVEKo3OpkIPzd_4_95CpHXF1MaW18ww5h_NShQnUrN7myrBfc-UbHsqC1YEBAM2M-" + "3NMs8jjgcZHfZ1JjomZCjd5eUXz8R5Vl46uAlSbFAmxAfY1T-31qUB93eCL2iJfDc70OK2txohryntw9h-OePwQULJN0Eiwp" + "oI60HQFFlgC1g_crPIDakBTiEITrbO3OzrNeCQFBN-Ji4BTXq97TulCIRNneDLCUBSRE1A"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9103, "passthrough"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9105, "passthrough"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + + assertOK(response); } @Test(description = "Test JWT Token propagation with JWT auth as the inbound authentication mechanism, with " + @@ -80,10 +77,9 @@ public void testTokenPropagationWithJwtAuthInboundAndTokenReissuing() throws Exc "ksSeIT9McZxjPiSX1FR-nIUTcJ9anaoQVEKo3OpkIPzd_4_95CpHXF1MaW18ww5h_NShQnUrN7myrBfc-UbHsqC1YEBAM2M-" + "3NMs8jjgcZHfZ1JjomZCjd5eUXz8R5Vl46uAlSbFAmxAfY1T-31qUB93eCL2iJfDc70OK2txohryntw9h-OePwQULJN0Eiwp" + "oI60HQFFlgC1g_crPIDakBTiEITrbO3OzrNeCQFBN-Ji4BTXq97TulCIRNneDLCUBSRE1A"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9105, "passthrough"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9107, "passthrough"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 200, "Response code mismatched"); + assertOK(response); } @Test(description = "Negative test for JWT Token propagation with JWT auth as the inbound authentication " + @@ -97,9 +93,8 @@ public void testTokenPropagationWithJwtAuthInboundAndTokenReissuingNegative() th "ksSeIT9McZxjPiSX1FR-nIUTcJ9anaoQVEKo3OpkIPzd_4_95CpHXF1MaW18ww5h_NShQnUrN7myrBfc-UbHsqC1YEBAM2M-" + "3NMs8jjgcZHfZ1JjomZCjd5eUXz8R5Vl46uAlSbFAmxAfY1T-31qUB93eCL2iJfDc70OK2txohryntw9h-OePwQULJN0Eiwp" + "oI60HQFFlgC1g_crPIDakBTiEITrbO3OzrNeCQFBN-Ji4BTXq97TulCIRNneDLCUBSRE1A"); - HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9107, "passthrough"), + HttpResponse response = HttpsClientRequest.doGet(serverInstance.getServiceURLHttps(9109, "passthrough"), headers, serverInstance.getServerHome()); - Assert.assertNotNull(response); - Assert.assertEquals(response.getResponseCode(), 401, "Response code mismatched"); + assertUnauthorized(response); } } diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authclients/oauth-client.bal b/tests/ballerina-integration-test/src/test/resources/auth/authclients/oauth-client.bal index 23acbe0cd214..89de5239cb23 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authclients/oauth-client.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authclients/oauth-client.bal @@ -17,7 +17,7 @@ import ballerina/http; // Test the client credentials grant type with valid credentials -http:Client clientEP1 = new("https://localhost:9095", config = { +http:Client clientEP1 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -33,7 +33,7 @@ http:Client clientEP1 = new("https://localhost:9095", config = { }); // Test the client credentials grant type with invalid client credentials -http:Client clientEP2 = new("https://localhost:9095", config = { +http:Client clientEP2 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -49,7 +49,7 @@ http:Client clientEP2 = new("https://localhost:9095", config = { }); // Test the client credentials grant type with a post-body bearer and valid credentials -http:Client clientEP3 = new("https://localhost:9095", config = { +http:Client clientEP3 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -66,7 +66,7 @@ http:Client clientEP3 = new("https://localhost:9095", config = { }); // Test the client credentials grant type with a post-body bearer and invalid credentials -http:Client clientEP4 = new("https://localhost:9095", config = { +http:Client clientEP4 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -83,7 +83,7 @@ http:Client clientEP4 = new("https://localhost:9095", config = { }); // Test the password grant type with valid credentials -http:Client clientEP5 = new("https://localhost:9095", config = { +http:Client clientEP5 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -101,7 +101,7 @@ http:Client clientEP5 = new("https://localhost:9095", config = { }); // Test the password grant type with valid credentials and a valid refresh config -http:Client clientEP6 = new("https://localhost:9095", config = { +http:Client clientEP6 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -123,7 +123,7 @@ http:Client clientEP6 = new("https://localhost:9095", config = { }); // Test the password grant type with an invalid username, password, and a valid refresh config -http:Client clientEP7 = new("https://localhost:9095", config = { +http:Client clientEP7 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -145,7 +145,7 @@ http:Client clientEP7 = new("https://localhost:9095", config = { }); // Test the password grant type with a bearer without credentials and a valid username and password -http:Client clientEP8 = new("https://localhost:9095", config = { +http:Client clientEP8 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -162,7 +162,7 @@ http:Client clientEP8 = new("https://localhost:9095", config = { }); // Test the direct token mode with valid credentials and without a refresh config -http:Client clientEP9 = new("https://localhost:9095", config = { +http:Client clientEP9 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -175,7 +175,7 @@ http:Client clientEP9 = new("https://localhost:9095", config = { }); // Test the direct token mode with an invalid access token and without a refresh config -http:Client clientEP10 = new("https://localhost:9095", config = { +http:Client clientEP10 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -188,7 +188,7 @@ http:Client clientEP10 = new("https://localhost:9095", config = { }); // Test the direct token mode with an invalid access token and a valid refresh config -http:Client clientEP11 = new("https://localhost:9095", config = { +http:Client clientEP11 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -208,7 +208,7 @@ http:Client clientEP11 = new("https://localhost:9095", config = { }); // Test the direct token mode (with the retrying request set as false) with an invalid access token and without a refresh config -http:Client clientEP12 = new("https://localhost:9095", config = { +http:Client clientEP12 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -222,7 +222,7 @@ http:Client clientEP12 = new("https://localhost:9095", config = { }); // Test the direct token mode (with the retrying request set as false) with an invalid access token and a valid refresh config -http:Client clientEP13 = new("https://localhost:9095", config = { +http:Client clientEP13 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { @@ -243,7 +243,7 @@ http:Client clientEP13 = new("https://localhost:9095", config = { }); // Test the direct token mode with an invalid access token and an invalid refresh config -http:Client clientEP14 = new("https://localhost:9095", config = { +http:Client clientEP14 = new("https://localhost:9195", config = { auth: { scheme: http:OAUTH2, config: { diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/01_authn_config_inheritance_auth_disabling_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/01_authn_config_inheritance_auth_disabling_test.bal deleted file mode 100644 index d951e7fd5a65..000000000000 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/01_authn_config_inheritance_auth_disabling_test.bal +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -// -// WSO2 Inc. licenses this file to you under the Apache License, -// Version 2.0 (the "License"); you may not use this file except -// in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -import ballerina/http; - -http:AuthProvider basicAuthProvider01 = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; - -listener http:Listener listener01 = new(9090, config = { - authProviders: [basicAuthProvider01], - secureSocket: { - keyStore: { - path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", - password: "ballerina" - } - } -}); - -@http:ServiceConfig { - basePath: "/echo", - authConfig: { - authentication: { enabled: true }, - scopes: ["xxx", "aaa"] - } -} -service echo01 on listener01 { - - @http:ResourceConfig { - methods: ["GET"], - path: "/test", - authConfig: { - authentication: { enabled: false } - } - } - resource function echo(http:Caller caller, http:Request req) { - checkpanic caller->respond(()); - } -} - diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/01_authn_config_inheritance_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/01_authn_config_inheritance_test.bal new file mode 100644 index 000000000000..c708c4d61ad3 --- /dev/null +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/01_authn_config_inheritance_test.bal @@ -0,0 +1,91 @@ +// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/auth; +import ballerina/http; + +auth:ConfigAuthStoreProvider basicAuthProvider01 = new; +http:BasicAuthnHandler basicAuthnHandler01 = new(basicAuthProvider01); + +listener http:Listener listener01 = new(9090, config = { + auth: { + authnHandlers: [basicAuthnHandler01] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" + } + } +}); + +@http:ServiceConfig { + basePath: "/echo1", + auth: { + enabled: true + } +} +service echo01_1 on listener01 { + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true + } + } + resource function test1(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: false + } + } + resource function test2(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } +} + +@http:ServiceConfig { + basePath: "/echo2", + auth: { + enabled: false + } +} +service echo01_2 on listener01 { + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true + } + } + resource function test1(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: false + } + } + resource function test2(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } +} diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/02_authn_config_inheritance_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/02_authn_config_inheritance_test.bal deleted file mode 100644 index 620280c2bcf0..000000000000 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/02_authn_config_inheritance_test.bal +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -// -// WSO2 Inc. licenses this file to you under the Apache License, -// Version 2.0 (the "License"); you may not use this file except -// in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -import ballerina/http; - -http:AuthProvider basicAuthProvider02 = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; - -listener http:Listener listener02 = new(9091, config = { - authProviders: [basicAuthProvider02], - secureSocket: { - keyStore: { - path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", - password: "ballerina" - } - } -}); - -@http:ServiceConfig { - basePath: "/echo", - authConfig: { - authentication: { enabled: false }, - scopes: ["xxx", "aaa"] - } -} -service echo02 on listener02 { - - @http:ResourceConfig { - methods: ["GET"], - path: "/test", - authConfig: { - authentication: { enabled: true } - } - } - resource function echo(http:Caller caller, http:Request req) { - checkpanic caller->respond(()); - } -} diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/02_authz_config_inheritance_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/02_authz_config_inheritance_test.bal new file mode 100644 index 000000000000..f6f918877606 --- /dev/null +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/02_authz_config_inheritance_test.bal @@ -0,0 +1,187 @@ +// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/auth; +import ballerina/http; + +auth:ConfigAuthStoreProvider basicAuthProvider02 = new; +http:BasicAuthnHandler basicAuthnHandler02 = new(basicAuthProvider02); + +listener http:Listener listener02_1 = new(9091, config = { + auth: { + authnHandlers: [basicAuthnHandler02], + scopes: ["scope1"] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" + } + } +}); + +listener http:Listener listener02_2 = new(9092, config = { + auth: { + authnHandlers: [basicAuthnHandler02], + scopes: ["scope4"] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" + } + } +}); + +listener http:Listener listener02_3 = new(9093, config = { + auth: { + authnHandlers: [basicAuthnHandler02] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" + } + } +}); + +@http:ServiceConfig { + basePath: "/echo1", + auth: { + enabled: true, + scopes: ["scope3"] + } +} +service echo02_1 on listener02_1, listener02_2, listener02_3 { + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true, + scopes: ["scope1", "scope2"] + } + } + resource function test1(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true, + scopes: ["scope3", "scope4"] + } + } + resource function test2(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } + + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true + } + } + resource function test3(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } +} + +@http:ServiceConfig { + basePath: "/echo2", + auth: { + enabled: true, + scopes: ["scope4"] + } +} +service echo02_2 on listener02_1, listener02_2, listener02_3 { + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true, + scopes: ["scope1", "scope2"] + } + } + resource function test1(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true, + scopes: ["scope3", "scope4"] + } + } + resource function test2(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } + + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true + } + } + resource function test3(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } +} + +@http:ServiceConfig { + basePath: "/echo3", + auth: { + enabled: true + } +} +service echo02_3 on listener02_1, listener02_2, listener02_3 { + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true, + scopes: ["scope1", "scope2"] + } + } + resource function test1(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true, + scopes: ["scope3", "scope4"] + } + } + resource function test2(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } + + + @http:ResourceConfig { + methods: ["GET"], + auth: { + enabled: true + } + } + resource function test3(http:Caller caller, http:Request req) { + checkpanic caller->respond(()); + } +} diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/03_authz_config_inheritance_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/03_authz_config_inheritance_test.bal deleted file mode 100644 index 153f7d68fc38..000000000000 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/03_authz_config_inheritance_test.bal +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -// -// WSO2 Inc. licenses this file to you under the Apache License, -// Version 2.0 (the "License"); you may not use this file except -// in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -import ballerina/http; - -http:AuthProvider basicAuthProvider03 = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; - -listener http:Listener listener03 = new(9092, config = { - authProviders: [basicAuthProvider03], - secureSocket: { - keyStore: { - path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", - password: "ballerina" - } - } -}); - -@http:ServiceConfig { - basePath: "/echo", - authConfig: { - authentication: { enabled: true }, - scopes: ["xxx"] - } -} -service echo03 on listener03 { - - @http:ResourceConfig { - methods: ["GET"], - path: "/test", - authConfig: { - scopes: ["scope2", "scope4"] - } - } - resource function echo(http:Caller caller, http:Request req) { - checkpanic caller->respond(()); - } -} diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/04_resource_level_auth_config_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/03_resource_level_auth_config_test.bal similarity index 69% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/04_resource_level_auth_config_test.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/03_resource_level_auth_config_test.bal index 327e28429c90..d6e87b8775f6 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/04_resource_level_auth_config_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/03_resource_level_auth_config_test.bal @@ -14,15 +14,16 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider basicAuthProvider04 = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +auth:ConfigAuthStoreProvider basicAuthProvider03 = new; +http:BasicAuthnHandler basicAuthnHandler03 = new(basicAuthProvider03); -listener http:Listener listener04 = new(9093, config = { - authProviders: [basicAuthProvider04], +listener http:Listener listener03 = new(9094, config = { + auth: { + authnHandlers: [basicAuthnHandler03] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -34,17 +35,16 @@ listener http:Listener listener04 = new(9093, config = { @http:ServiceConfig { basePath: "/echo" } -service echo04 on listener04 { +service echo03 on listener03 { @http:ResourceConfig { methods: ["GET"], - path: "/test", - authConfig: { - authentication: { enabled: true }, - scopes: ["scope2"] + auth: { + enabled: true, + scopes: ["scope4"] } } - resource function echo(http:Caller caller, http:Request req) { + resource function test(http:Caller caller, http:Request req) { checkpanic caller->respond(()); } } diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/12_secure_service_wrong_provider_id_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/04_service_level_auth_config_test.bal similarity index 66% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/12_secure_service_wrong_provider_id_test.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/04_service_level_auth_config_test.bal index e3f4fa4dc043..5891dc3ffdc0 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/12_secure_service_wrong_provider_id_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/04_service_level_auth_config_test.bal @@ -14,16 +14,16 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider basicAuthProvider12 = { - id: "basic1", - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +auth:ConfigAuthStoreProvider basicAuthProvider04 = new; +http:BasicAuthnHandler basicAuthnHandler04 = new(basicAuthProvider04); -listener http:Listener listener12 = new(9194, config = { - authProviders: [basicAuthProvider12], +listener http:Listener listener04 = new(9095, config = { + auth: { + authnHandlers: [basicAuthnHandler04] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -34,19 +34,17 @@ listener http:Listener listener12 = new(9194, config = { @http:ServiceConfig { basePath: "/echo", - authConfig: { - authProviders: ["basic2"], - authentication: { enabled: true }, - scopes: ["scope2"] + auth: { + enabled: true, + scopes: ["scope4"] } } -service echo12 on listener12 { +service echo04 on listener04 { @http:ResourceConfig { - methods: ["GET"], - path: "/test" + methods: ["GET"] } - resource function echo(http:Caller caller, http:Request req) { + resource function test(http:Caller caller, http:Request req) { checkpanic caller->respond(()); } -} \ No newline at end of file +} diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/07_auth_test_without_annotations.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/05_auth_test_without_annotations_test.bal similarity index 68% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/07_auth_test_without_annotations.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/05_auth_test_without_annotations_test.bal index 5146e9666cca..96263ae35269 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/07_auth_test_without_annotations.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/05_auth_test_without_annotations_test.bal @@ -14,15 +14,16 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider basicAuthProvider07 = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +auth:ConfigAuthStoreProvider basicAuthProvider05 = new; +http:BasicAuthnHandler basicAuthnHandler05 = new(basicAuthProvider05); -listener http:Listener listener07 = new(9098, config = { - authProviders: [basicAuthProvider07], +listener http:Listener listener05 = new(9096, config = { + auth: { + authnHandlers: [basicAuthnHandler05] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -31,9 +32,12 @@ listener http:Listener listener07 = new(9098, config = { } }); -service echo7 on listener07 { +@http:ServiceConfig { + basePath: "/echo" +} +service echo05 on listener05 { - resource function test7(http:Caller caller, http:Request req) { + resource function test(http:Caller caller, http:Request req) { checkpanic caller->respond(()); } } diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/05_service_level_auth_config_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/06_authn_with_multiple_handlers.bal similarity index 50% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/05_service_level_auth_config_test.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/06_authn_with_multiple_handlers.bal index 269a04210053..03dc47034b23 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/05_service_level_auth_config_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/06_authn_with_multiple_handlers.bal @@ -14,15 +14,37 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider basicAuthProvider05 = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +auth:JWTAuthProvider jwtAuthProvider06_1 = new({ + issuer: "example1", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" + } +}); + +auth:JWTAuthProvider jwtAuthProvider06_2 = new({ + issuer: "example2", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" + } +}); + + +http:JwtAuthnHandler jwtAuthnHandler06_1 = new(jwtAuthProvider06_1); +http:JwtAuthnHandler jwtAuthnHandler06_2 = new(jwtAuthProvider06_2); -listener http:Listener listener05 = new(9094, config = { - authProviders: [basicAuthProvider05], +listener http:Listener listener06 = new(9097, config = { + auth: { + authnHandlers: [jwtAuthnHandler06_1, jwtAuthnHandler06_2] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -32,27 +54,11 @@ listener http:Listener listener05 = new(9094, config = { }); @http:ServiceConfig { - basePath: "/echo", - authConfig: { - authentication: { enabled: true }, - scopes: ["scope2"] - } + basePath: "/echo" } -service echo05 on listener05 { - - @http:ResourceConfig { - methods: ["GET"], - path: "/test" - } - resource function echo(http:Caller caller, http:Request req) { - checkpanic caller->respond(()); - } +service echo06 on listener06 { - @http:ResourceConfig { - methods: ["GET"], - path: "/path/{id}" - } - resource function path(http:Caller caller, http:Request req, string id) { + resource function test(http:Caller caller, http:Request req) { checkpanic caller->respond(()); } } diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/09_authn_with_different_scopes.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/07_authn_with_different_scopes_test.bal similarity index 61% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/09_authn_with_different_scopes.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/07_authn_with_different_scopes_test.bal index 9686322d6fe2..8bc5102d958a 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/09_authn_with_different_scopes.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/07_authn_with_different_scopes_test.bal @@ -14,23 +14,25 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider jwtAuthProvider3 = { - scheme: http:JWT_AUTH, - config: { - issuer: "ballerina", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider07 = new({ + issuer: "ballerina", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); + +http:JwtAuthnHandler jwtAuthnHandler07 = new(jwtAuthProvider07); -listener http:Listener listener09 = new(9100, config = { - authProviders: [jwtAuthProvider3], +listener http:Listener listener07 = new(9098, config = { + auth: { + authnHandlers: [jwtAuthnHandler07] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -40,13 +42,14 @@ listener http:Listener listener09 = new(9100, config = { }); @http:ServiceConfig { - authConfig: { + basePath: "/echo", + auth: { scopes: ["test-scope"] } } -service echo9 on listener09 { +service echo07 on listener07 { - resource function test9(http:Caller caller, http:Request req) { + resource function test(http:Caller caller, http:Request req) { checkpanic caller->respond(()); } } diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/13_authn_with_expired_certificate.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/08_authn_with_expired_certificate_test.bal similarity index 60% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/13_authn_with_expired_certificate.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/08_authn_with_expired_certificate_test.bal index 1a7c659a1ca5..407f86518139 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/13_authn_with_expired_certificate.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/08_authn_with_expired_certificate_test.bal @@ -14,23 +14,25 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider jwtAuthProvider4 = { - scheme: http:JWT_AUTH, - config: { - issuer:"ballerina", - audience: ["ballerina.io"], - certificateAlias: "cert", - trustStore: { - path: "${ballerina.home}/../../../src/test/resources/auth/testtruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider08 = new({ + issuer:"ballerina", + audience: ["ballerina.io"], + certificateAlias: "cert", + trustStore: { + path: "../../../src/test/resources/auth/testtruststore.p12", + password: "ballerina" } -}; +}); -listener http:Listener listener13 = new(9101, config = { - authProviders:[jwtAuthProvider4], +http:JwtAuthnHandler jwtAuthnHandler08 = new(jwtAuthProvider08); + +listener http:Listener listener08 = new(9099, config = { + auth: { + authnHandlers: [jwtAuthnHandler08] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -39,9 +41,12 @@ listener http:Listener listener13 = new(9101, config = { } }); -service echo13 on listener13 { +@http:ServiceConfig { + basePath: "/echo" +} +service echo08 on listener08 { - resource function test13 (http:Caller caller, http:Request req) { + resource function test(http:Caller caller, http:Request req) { checkpanic caller -> respond(()); } } diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/08_authn_with_multiple_providers.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/08_authn_with_multiple_providers.bal deleted file mode 100644 index cd24caa1e195..000000000000 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/08_authn_with_multiple_providers.bal +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -// -// WSO2 Inc. licenses this file to you under the Apache License, -// Version 2.0 (the "License"); you may not use this file except -// in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -import ballerina/http; - -http:AuthProvider jwtAuthProvider1 = { - scheme: http:JWT_AUTH, - config: { - issuer: "example1", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } - } -}; - -http:AuthProvider jwtAuthProvider2 = { - scheme: http:JWT_AUTH, - config: { - issuer: "example2", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } - } -}; - -listener http:Listener listener08 = new(9099, config = { - authProviders: [jwtAuthProvider1, jwtAuthProvider2], - secureSocket: { - keyStore: { - path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", - password: "ballerina" - } - } -}); - -service echo8 on listener08 { - - resource function test8(http:Caller caller, http:Request req) { - checkpanic caller->respond(()); - } -} diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/14_authn_with_expired_certificate_with_no_expiry_validation.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/09_authn_with_expired_certificate_with_no_expiry_validation.bal similarity index 58% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/14_authn_with_expired_certificate_with_no_expiry_validation.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/09_authn_with_expired_certificate_with_no_expiry_validation.bal index d8849466ef23..099ad8308467 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/14_authn_with_expired_certificate_with_no_expiry_validation.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/09_authn_with_expired_certificate_with_no_expiry_validation.bal @@ -14,24 +14,26 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider jwtAuthProvider14 = { - scheme: http:JWT_AUTH, - config: { - issuer:"ballerina", - audience: ["ballerina.io"], - certificateAlias: "cert", - validateCertificate: false, - trustStore: { - path: "../../../src/test/resources/auth/testtruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider09 = new({ + issuer:"ballerina", + audience: ["ballerina.io"], + certificateAlias: "cert", + validateCertificate: false, + trustStore: { + path: "../../../src/test/resources/auth/testtruststore.p12", + password: "ballerina" } -}; +}); -listener http:Listener listener14 = new(9102, config = { - authProviders:[jwtAuthProvider14], +http:JwtAuthnHandler jwtAuthnHandler09 = new(jwtAuthProvider09); + +listener http:Listener listener09 = new(9100, config = { + auth: { + authnHandlers: [jwtAuthnHandler09] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -40,9 +42,12 @@ listener http:Listener listener14 = new(9102, config = { } }); -service echo14 on listener14 { +@http:ServiceConfig { + basePath: "/echo" +} +service echo09 on listener09 { - resource function test14 (http:Caller caller, http:Request req) { + resource function test(http:Caller caller, http:Request req) { checkpanic caller -> respond(()); } } diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/10_token_propagation_disabled_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/10_token_propagation_disabled_test.bal index 8557754cf98e..0e8d4052e0b1 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/10_token_propagation_disabled_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/10_token_propagation_disabled_test.bal @@ -14,16 +14,17 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; // token propagation is set to false by default -http:AuthProvider basicAuthProvider10 = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +auth:ConfigAuthStoreProvider basicAuthProvider10 = new; +http:BasicAuthnHandler basicAuthnHandler10 = new(basicAuthProvider10); -listener http:Listener listener10_1 = new(9190, config = { - authProviders: [basicAuthProvider10], +listener http:Listener listener10_1 = new(9101, config = { + auth: { + authnHandlers: [basicAuthnHandler10] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -33,10 +34,10 @@ listener http:Listener listener10_1 = new(9190, config = { }); // client will not propagate JWT -http:Client nyseEP = new("https://localhost:9195"); +http:Client nyseEP = new("https://localhost:9102"); @http:ServiceConfig { basePath: "/passthrough" } -service passthroughService on listener10_1 { +service passthroughService10 on listener10_1 { @http:ResourceConfig { methods: ["GET"], @@ -56,21 +57,22 @@ service passthroughService on listener10_1 { } } -http:AuthProvider jwtAuthProvider10 = { - scheme: http:JWT_AUTH, - config: { - issuer: "ballerina", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider10 = new({ + issuer: "ballerina", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); + +http:JwtAuthnHandler jwtAuthnHandler10 = new(jwtAuthProvider10); -listener http:Listener listener10_2 = new(9195, config = { - authProviders: [jwtAuthProvider10], +listener http:Listener listener10_2 = new(9102, config = { + auth: { + authnHandlers: [jwtAuthnHandler10] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -80,7 +82,7 @@ listener http:Listener listener10_2 = new(9195, config = { }); @http:ServiceConfig { basePath: "/nyseStock" } -service nyseStockQuote on listener10_2 { +service nyseStockQuote10 on listener10_2 { @http:ResourceConfig { methods: ["GET"], diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/11_token_propagation_basic_auth_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/11_token_propagation_basic_auth_test.bal index d70b363102ba..f21b59d21a92 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/11_token_propagation_basic_auth_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/11_token_propagation_basic_auth_test.bal @@ -14,15 +14,16 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider basicAuthProvider11 = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +auth:ConfigAuthStoreProvider basicAuthProvider11 = new; +http:BasicAuthnHandler basicAuthnHandler11 = new(basicAuthProvider11); -listener http:Listener listener11 = new(9192, config = { - authProviders: [basicAuthProvider11], +listener http:Listener listener11_1 = new(9103, config = { + auth: { + authnHandlers: [basicAuthnHandler11] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -31,7 +32,7 @@ listener http:Listener listener11 = new(9192, config = { } }); -http:Client nyseEP03 = new("https://localhost:9193", config = { +http:Client nyseEP03 = new("https://localhost:9104", config = { auth: { scheme: http:JWT_AUTH, config: { @@ -50,7 +51,7 @@ http:Client nyseEP03 = new("https://localhost:9193", config = { }); @http:ServiceConfig { basePath: "/passthrough" } -service passthroughService03 on listener11 { +service passthroughService11 on listener11_1 { @http:ResourceConfig { methods: ["GET"], @@ -70,31 +71,32 @@ service passthroughService03 on listener11 { } } -http:AuthProvider jwtAuthProvider03 = { - scheme: http:JWT_AUTH, - config: { - issuer: "ballerina", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider11 = new({ + issuer: "ballerina", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); -listener http:Listener listener2 = new(9193, config = { - authProviders: [jwtAuthProvider03], - secureSocket: { - keyStore: { - path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", - password: "ballerina" - } +http:JwtAuthnHandler jwtAuthnHandler11 = new(jwtAuthProvider11); + +listener http:Listener listener11_2 = new(9104, config = { + auth: { + authnHandlers: [jwtAuthnHandler11] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" } - }); + } +}); @http:ServiceConfig { basePath: "/nyseStock" } -service nyseStockQuote03 on listener2 { +service nyseStockQuote11 on listener11_2 { @http:ResourceConfig { methods: ["GET"], diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/15_token_propagation_jwt_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/12_token_propagation_jwt_test.bal similarity index 60% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/15_token_propagation_jwt_test.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/12_token_propagation_jwt_test.bal index 779da3c35038..8590a8cee4ec 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/15_token_propagation_jwt_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/12_token_propagation_jwt_test.bal @@ -14,23 +14,25 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider basicAuthProvider15 = { - scheme: http:JWT_AUTH, - config: { - issuer: "example1", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider12_1 = new({ + issuer: "example1", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); + +http:JwtAuthnHandler jwtAuthnHandler12_1 = new(jwtAuthProvider12_1); -listener http:Listener listener15_1 = new(9103, config = { - authProviders: [basicAuthProvider15], +listener http:Listener listener12_1 = new(9105, config = { + auth: { + authnHandlers: [jwtAuthnHandler12_1] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -39,21 +41,21 @@ listener http:Listener listener15_1 = new(9103, config = { } }); -http:Client nyseEP15 = new("https://localhost:9104", config = { +http:Client nyseEP12 = new("https://localhost:9106", config = { auth: { scheme: http:JWT_AUTH } }); @http:ServiceConfig { basePath: "/passthrough" } -service passthroughService15 on listener15_1 { +service passthroughService12 on listener12_1 { @http:ResourceConfig { methods: ["GET"], path: "/" } resource function passthrough(http:Caller caller, http:Request clientRequest) { - var response = nyseEP15->get("/nyseStock/stocks", message = untaint clientRequest); + var response = nyseEP12->get("/nyseStock/stocks", message = untaint clientRequest); if (response is http:Response) { checkpanic caller->respond(response); } else { @@ -66,31 +68,32 @@ service passthroughService15 on listener15_1 { } } -http:AuthProvider jwtAuthProvider15 = { - scheme: http:JWT_AUTH, - config: { - issuer: "example1", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider12_2 = new({ + issuer: "example1", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); -listener http:Listener listener15_2 = new(9104, config = { - authProviders: [jwtAuthProvider15], - secureSocket: { - keyStore: { - path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", - password: "ballerina" - } +http:JwtAuthnHandler jwtAuthnHandler12_2 = new(jwtAuthProvider12_2); + +listener http:Listener listener12_2 = new(9106, config = { + auth: { + authnHandlers: [jwtAuthnHandler12_2] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" } - }); + } +}); @http:ServiceConfig { basePath: "/nyseStock" } -service nyseStockQuote15 on listener15_2 { +service nyseStockQuote12 on listener12_2 { @http:ResourceConfig { methods: ["GET"], diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/16_token_propagation_jwt_reissuing_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/13_token_propagation_jwt_reissuing_test.bal similarity index 64% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/16_token_propagation_jwt_reissuing_test.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/13_token_propagation_jwt_reissuing_test.bal index f906a3f513e1..90f6294600e7 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/16_token_propagation_jwt_reissuing_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/13_token_propagation_jwt_reissuing_test.bal @@ -14,23 +14,25 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider basicAuthProvider16 = { - scheme: http:JWT_AUTH, - config: { - issuer: "example1", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider13_1 = new({ + issuer: "example1", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); -listener http:Listener listener16_1 = new(9105, config = { - authProviders: [basicAuthProvider16], +http:JwtAuthnHandler jwtAuthnHandler13_1 = new(jwtAuthProvider13_1); + +listener http:Listener listener13_1 = new(9107, config = { + auth: { + authnHandlers: [jwtAuthnHandler13_1] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -39,7 +41,7 @@ listener http:Listener listener16_1 = new(9105, config = { } }); -http:Client nyseEP16 = new("https://localhost:9106", config = { +http:Client nyseEP13 = new("https://localhost:9108", config = { auth: { scheme: http:JWT_AUTH, config: { @@ -58,14 +60,14 @@ http:Client nyseEP16 = new("https://localhost:9106", config = { }); @http:ServiceConfig { basePath: "/passthrough" } -service passthroughService16 on listener16_1 { +service passthroughService13 on listener13_1 { @http:ResourceConfig { methods: ["GET"], path: "/" } resource function passthrough(http:Caller caller, http:Request clientRequest) { - var response = nyseEP16->get("/nyseStock/stocks", message = untaint clientRequest); + var response = nyseEP13->get("/nyseStock/stocks", message = untaint clientRequest); if (response is http:Response) { checkpanic caller->respond(response); } else { @@ -78,31 +80,32 @@ service passthroughService16 on listener16_1 { } } -http:AuthProvider jwtAuthProvider16 = { - scheme: http:JWT_AUTH, - config: { - issuer: "example2", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider13_2 = new({ + issuer: "example2", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); -listener http:Listener listener16_2 = new(9106, config = { - authProviders: [jwtAuthProvider16], - secureSocket: { - keyStore: { - path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", - password: "ballerina" - } +http:JwtAuthnHandler jwtAuthnHandler13_2 = new(jwtAuthProvider13_2); + +listener http:Listener listener13_2 = new(9108, config = { + auth: { + authnHandlers: [jwtAuthnHandler13_2] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" } - }); + } +}); @http:ServiceConfig { basePath: "/nyseStock" } -service nyseStockQuote16 on listener16_2 { +service nyseStockQuote13 on listener13_2 { @http:ResourceConfig { methods: ["GET"], diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/17_token_propagation_jwt_reissuing_negative_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/14_token_propagation_jwt_reissuing_negative_test.bal similarity index 68% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/17_token_propagation_jwt_reissuing_negative_test.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/14_token_propagation_jwt_reissuing_negative_test.bal index 25e3d7f1b580..669dc02edd9d 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/17_token_propagation_jwt_reissuing_negative_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/14_token_propagation_jwt_reissuing_negative_test.bal @@ -14,23 +14,25 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/http; -http:AuthProvider basicAuthProvider17 = { - scheme: http:JWT_AUTH, - config: { - issuer: "example1", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider14_1 = new({ + issuer: "example1", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); -listener http:Listener listener17_1 = new(9107, config = { - authProviders: [basicAuthProvider17], +http:JwtAuthnHandler jwtAuthnHandler14_1 = new(jwtAuthProvider14_1); + +listener http:Listener listener14_1 = new(9109, config = { + auth: { + authnHandlers: [jwtAuthnHandler14_1] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -39,7 +41,7 @@ listener http:Listener listener17_1 = new(9107, config = { } }); -http:Client nyseEP17 = new("https://localhost:9108", config = { +http:Client nyseEP14 = new("https://localhost:9110", config = { auth: { scheme: http:JWT_AUTH, config: { @@ -58,14 +60,14 @@ http:Client nyseEP17 = new("https://localhost:9108", config = { }); @http:ServiceConfig { basePath: "/passthrough" } -service passthroughService17 on listener17_1 { +service passthroughService14 on listener14_1 { @http:ResourceConfig { methods: ["GET"], path: "/" } resource function passthrough(http:Caller caller, http:Request clientRequest) { - var response = nyseEP17->get("/nyseStock/stocks", message = untaint clientRequest); + var response = nyseEP14->get("/nyseStock/stocks", message = untaint clientRequest); if (response is http:Response) { checkpanic caller->respond(response); } else { @@ -78,21 +80,22 @@ service passthroughService17 on listener17_1 { } } -http:AuthProvider jwtAuthProvider17 = { - scheme: http:JWT_AUTH, - config: { - issuer: "example2aaaaaaaaaaaaaa", - audience: ["ballerina"], - certificateAlias: "ballerina", - trustStore: { - path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", - password: "ballerina" - } +auth:JWTAuthProvider jwtAuthProvider14_2 = new({ + issuer: "example2aaaaaaaaaaaaaa", + audience: ["ballerina"], + certificateAlias: "ballerina", + trustStore: { + path: "${ballerina.home}/bre/security/ballerinaTruststore.p12", + password: "ballerina" } -}; +}); + +http:JwtAuthnHandler jwtAuthnHandler14_2 = new(jwtAuthProvider14_2); -listener http:Listener listener17_2 = new(9108, config = { - authProviders: [jwtAuthProvider17], +listener http:Listener listener14_2 = new(9110, config = { + auth: { + authnHandlers: [jwtAuthnHandler14_2] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -102,7 +105,7 @@ listener http:Listener listener17_2 = new(9108, config = { }); @http:ServiceConfig { basePath: "/nyseStock" } -service nyseStockQuote17 on listener17_2 { +service nyseStockQuote14 on listener14_2 { @http:ResourceConfig { methods: ["GET"], diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/ldap_auth_store_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/15_ldap_auth_store_test.bal similarity index 85% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/ldap_auth_store_test.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/15_ldap_auth_store_test.bal index d7345455f0fd..99bdf52d48d9 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/ldap_auth_store_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/15_ldap_auth_store_test.bal @@ -17,7 +17,7 @@ import ballerina/auth; import ballerina/http; -auth:LdapAuthProviderConfig ldapAuthProviderConfig = { +auth:LdapAuthStoreProviderConfig ldapConfig02 = { domainName: "ballerina.io", connectionURL: "ldap://localhost:9389", connectionName: "uid=admin,ou=system", @@ -40,15 +40,13 @@ auth:LdapAuthProviderConfig ldapAuthProviderConfig = { retryAttempts: 3 }; -http:AuthProvider basicAuthProvider = { - id: "basic01", - scheme: http:BASIC_AUTH, - authStoreProvider: http:LDAP_AUTH_STORE, - config: ldapAuthProviderConfig -}; +auth:LdapAuthStoreProvider ldapAuthStoreProvider02 = new(ldapConfig02, "ldap01"); +http:BasicAuthnHandler ldapAuthnHandler02 = new(ldapAuthStoreProvider02); -listener http:Listener ep = new(9096, config = { - authProviders: [basicAuthProvider], +listener http:Listener ep = new(9111, config = { + auth: { + authnHandlers: [ldapAuthnHandler02] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -59,8 +57,8 @@ listener http:Listener ep = new(9096, config = { @http:ServiceConfig { basePath: "/ldapAuth", - authConfig: { - authentication: { enabled: true } + auth: { + enabled: true } } service helloService on ep { @@ -76,7 +74,7 @@ service helloService on ep { @http:ResourceConfig { methods: ["GET"], path: "/enableAuthz", - authConfig: { + auth: { scopes: ["test"] } } @@ -87,7 +85,7 @@ service helloService on ep { @http:ResourceConfig { methods: ["GET"], path: "/failAuthz", - authConfig: { + auth: { scopes: ["admin", "support"] } } diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/ldap_auth_store_authorization_test.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/16_ldap_auth_store_authz_test.bal similarity index 84% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/ldap_auth_store_authorization_test.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/16_ldap_auth_store_authz_test.bal index 93690ba79585..6cc69c3d1381 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/ldap_auth_store_authorization_test.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/16_ldap_auth_store_authz_test.bal @@ -17,7 +17,7 @@ import ballerina/auth; import ballerina/http; -auth:LdapAuthProviderConfig ldapConfig = { +auth:LdapAuthStoreProviderConfig ldapConfig01 = { domainName: "ballerina.io", connectionURL: "ldap://localhost:9389", connectionName: "uid=admin,ou=system", @@ -40,15 +40,13 @@ auth:LdapAuthProviderConfig ldapConfig = { retryAttempts: 3 }; -http:AuthProvider authProvider = { - id: "basic02", - scheme: http:BASIC_AUTH, - authStoreProvider: http:LDAP_AUTH_STORE, - config: ldapConfig -}; +auth:LdapAuthStoreProvider ldapAuthStoreProvider01 = new(ldapConfig01, "ldap01"); +http:BasicAuthnHandler ldapAuthnHandler01 = new(ldapAuthStoreProvider01); -listener http:Listener authEP = new(9097, config = { - authProviders: [authProvider], +listener http:Listener authEP = new(9112, config = { + auth: { + authnHandlers: [ldapAuthnHandler01] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", @@ -59,8 +57,8 @@ listener http:Listener authEP = new(9097, config = { @http:ServiceConfig { basePath: "/auth", - authConfig: { - authentication: { enabled: true } + auth: { + enabled: true } } service authService on authEP { @@ -68,7 +66,7 @@ service authService on authEP { @http:ResourceConfig { methods: ["GET"], path: "/failAuthz", - authConfig: { + auth: { scopes: ["admin", "support"] } } diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/17_authn_with_custom_handlers.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/17_authn_with_custom_handlers.bal new file mode 100644 index 000000000000..c51e642b0b69 --- /dev/null +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/17_authn_with_custom_handlers.bal @@ -0,0 +1,102 @@ +// Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/auth; +import ballerina/encoding; +import ballerina/http; +import ballerina/runtime; + +CustomAuthStoreProvider customAuthStoreProvider = new; +CustomAuthnHandler customAuthnHandler = new(customAuthStoreProvider); + +listener http:Listener listener17 = new(9113, config = { + auth: { + authnHandlers: [customAuthnHandler], + scopes: ["all"] + }, + secureSocket: { + keyStore: { + path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", + password: "ballerina" + } + } + }); + +@http:ServiceConfig { + basePath: "/echo" +} +service echo17 on listener17 { + resource function test(http:Caller caller, http:Request req) { + checkpanic caller->respond("Hello Ballerina!"); + } +} + + +// ---------- custom_authn_handler ---------- + +public type CustomAuthnHandler object { + + *http:AuthnHandler; + + public auth:AuthProvider authProvider; + + public function __init(auth:AuthProvider authProvider) { + self.authProvider = authProvider; + } +}; + +public function CustomAuthnHandler.handle(http:Request req) returns boolean|error { + var customAuthHeader = req.getHeader(http:AUTH_HEADER); + string credential = customAuthHeader.substring(6, customAuthHeader.length()).trim(); + return self.authProvider.authenticate(credential); +} + +public function CustomAuthnHandler.canHandle(http:Request req) returns boolean { + var customAuthHeader = req.getHeader(http:AUTH_HEADER); + return customAuthHeader.hasPrefix("Custom"); +} + + +// ---------- custom_auth_store_provider ---------- + +public type CustomAuthStoreProvider object { + + *auth:AuthProvider; + + public function authenticate(string credential) returns boolean|error { + string actualUsername = "abc"; + string actualPassword = "123"; + + string decodedHeaderValue = encoding:byteArrayToString(check encoding:decodeBase64(credential)); + string[] decodedCredentials = decodedHeaderValue.split(":"); + string username = decodedCredentials[0]; + string password = decodedCredentials[1]; + + boolean isAuthenticated = username == actualUsername && password == actualPassword; + if (isAuthenticated) { + runtime:Principal principal = runtime:getInvocationContext().principal; + principal.userId = username; + principal.username = username; + principal.scopes = self.getScopes(); + } + return isAuthenticated; + } + + public function getScopes() returns string[] { + string[] scopes = ["all"]; + return scopes; + } +}; diff --git a/tests/ballerina-integration-test/src/test/resources/auth/authservices/06_mock-oauth-service.bal b/tests/ballerina-integration-test/src/test/resources/auth/authservices/mock-oauth-service.bal similarity index 99% rename from tests/ballerina-integration-test/src/test/resources/auth/authservices/06_mock-oauth-service.bal rename to tests/ballerina-integration-test/src/test/resources/auth/authservices/mock-oauth-service.bal index 152360fa17e5..a29022bb0b06 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/authservices/06_mock-oauth-service.bal +++ b/tests/ballerina-integration-test/src/test/resources/auth/authservices/mock-oauth-service.bal @@ -369,7 +369,7 @@ function addToAccessTokenStore(string accessToken) { //The API endpoint, which is responsible for processing the request after validating the access token in the authorization header. // The token should be listed in the accessTokenStore, which keeps the tokens issued by the mock OAuth2 server. -listener http:Listener apiEndpoint = new(9095, config = { +listener http:Listener apiEndpoint = new(9195, config = { secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12", diff --git a/tests/ballerina-integration-test/src/test/resources/auth/ballerina.conf b/tests/ballerina-integration-test/src/test/resources/auth/ballerina.conf index 31cf435f1d6b..d27ffee93685 100644 --- a/tests/ballerina-integration-test/src/test/resources/auth/ballerina.conf +++ b/tests/ballerina-integration-test/src/test/resources/auth/ballerina.conf @@ -2,8 +2,8 @@ ["b7a.users.isuru"] password="xxx" -scopes="scope2" +scopes="scope4" ["b7a.users.ishara"] password="abc" -scopes="scope1" +scopes="scope1,scope2,scope3" diff --git a/tests/ballerina-integration-test/src/test/resources/testng.xml b/tests/ballerina-integration-test/src/test/resources/testng.xml index c358316f214b..c9d91847f9bc 100644 --- a/tests/ballerina-integration-test/src/test/resources/testng.xml +++ b/tests/ballerina-integration-test/src/test/resources/testng.xml @@ -102,18 +102,17 @@ - + + + + + - - - - - - + diff --git a/tests/ballerina-integration-test/src/test/resources/websub/advanced_services/01_websub_publisher.bal b/tests/ballerina-integration-test/src/test/resources/websub/advanced_services/01_websub_publisher.bal index 2979a914953d..4aabab988c0e 100644 --- a/tests/ballerina-integration-test/src/test/resources/websub/advanced_services/01_websub_publisher.bal +++ b/tests/ballerina-integration-test/src/test/resources/websub/advanced_services/01_websub_publisher.bal @@ -14,6 +14,7 @@ // specific language governing permissions and limitations // under the License. +import ballerina/auth; import ballerina/h2; import ballerina/http; import ballerina/io; @@ -25,13 +26,13 @@ const string WEBSUB_PERSISTENCE_TOPIC_ONE = "http://one.persistence.topic.com"; const string WEBSUB_PERSISTENCE_TOPIC_TWO = "http://two.persistence.topic.com"; const string WEBSUB_TOPIC_ONE = "http://one.websub.topic.com"; -http:AuthProvider basicAuthProvider = { - scheme: http:BASIC_AUTH, - authStoreProvider: http:CONFIG_AUTH_STORE -}; +auth:ConfigAuthStoreProvider basicAuthProvider = new; +http:BasicAuthnHandler basicAuthnHandler = new(basicAuthProvider); http:ServiceEndpointConfiguration hubListenerConfig = { - authProviders: [basicAuthProvider], + auth: { + authnHandlers: [basicAuthnHandler] + }, secureSocket: { keyStore: { path: "${ballerina.home}/bre/security/ballerinaKeystore.p12",