Kikaha has a very tiny and non-intrusive Security API written over Undertow's Security API. Basically it has a few components that together allow you to protect your resources. Let's checkout the main components you'll usually need to deal with:
Authentication mechanisms is responsible for extract credentials from HTTP requests. Usually they does not check if the credentials are valid, but delegates the validation to the IdentityManager defined on the matched Authentication Rule. Out-of-box only a few Authentication Mechanisms are provided. They are very common and allow developers to get started very quickly. Bellow they are listed and identified by its own alias
:
Now lets talk about its alias. All Authentication Mechanism should be defined on the configuration entry server.auth.authentication-mechanisms
on a alias: class.Name
form (see sample the configuration file bellow). The alias, as we discussed before, are used on the Authentication Rules and avoids you to repeat the Authentication Mechanism's Class Canonical Name every time you need to use it to protect a specific resource.
Here are a sample code with the default Authentication Mechanisms that comes out-of-box with Kikaha:
server:
auth:
auth-mechanisms:
# available on kikaha-core's module
default: kikaha.core.modules.security.BasicAuthenticationMechanism
basic: kikaha.core.modules.security.BasicAuthenticationMechanism
form: kikaha.core.modules.security.FormAuthenticationMechanism
# available on kikaha-jackson's module
json: kikaha.urouting.serializers.jackson.JSONAuthenticationMechanism
If none of the above described mechanisms fits your needs you can easily create your own by implementing the interface kikaha.core.modules.security.AuthenticationMechanism
and defining an alias for it. Please, keep in mind that cood Authentication Mechanisms usually delegates the Credential Validation to a proper IdentityManager.
Identity Managers are responsible for ensure credentials are valid. It is also responsible to retrieve the Account
and its Roles
from the place you've stored your data. Out-of-box there a few Identity Managers available:
A more sophisticated Identity Manager could be developed by implementing the kikaha.core.modules.security.IdentityManager
interface. A much simpler approach is to extends kikaha.core.modules.security.AbstractPasswordBasedIdentityManager
.
The code bellow illustrates how to create your own Identity Manager with fixed username and password. Developers are encouraged to follow this pattern to provide their own Identity Manager.
package sample;
import kikaha.core.modules.security.*;
public class CustomIdentityManager extends AbstractPasswordBasedIdentityManager {
final String username = "admin";
final String password = "password";
final String defaultRole = "admin";
@Override
public Account retrieveAccountFor( String id, String password ) {
if ( this.username.equals( id ) && this.password.equals( password ) )
return new FixedUsernameAndRolesAccount( username, defaultRole );
return null;
}
}
Don't forget to register an alias to your custom Identity Manager.
server:
auth:
identity-manager:
custom: sample.CustomIdentityManager
Whenever you need to handle how to store or match a password you can use a Password Encoder to keep you credentials safe. Basically, out-of-box, there are two password encoders available:
kikaha.core.modules.security.PlainTextPasswordEncoder
You can define which Password Encoder will be used on your application by simply pointing the configuration entry server.auth.password-encoder
to one of above mentioned classes.
server:
auth:
password-encoder: kikaha.core.modules.security.PlainTextPasswordEncoder
In order to protect your resources and forces the authentication process you should include an entry in server.auth.rules
array on your configuration file. It will behaves like ACL where the first rule that matches the request will be applied. If no rule was matched, then the route will be executed as non-authenticated resource. Bellow we defined a rule the require authentication for any request made at "/protected/" resource and its sub-locations.
server:
auth:
rules:
- pattern: "/protected/*"
identity-manager: ["custom"]
auth-mechanisms: ["basic"]
expected-roles: []
exclude-patterns: [ "*.ico","*.js" ]
As you can note, there is some attributes we can define for each rule:
If for some reason you have to repeat some exclusion-patterns on every rule you made, you rather define then at server.auth.default-excluded-patterns
.
Also, you can simplify your configuration file by overriding the 'default' identity-manager
and authentication-mechanism
. Bellow a more usual authentication rules should look like.
server:
auth:
# Using my custom
identity-manager: { default: sample.CustomIdentityManager }
default-excluded-patterns: ["*.ico","*.css","*.js","*.png","*.jpg"]
rules:
# Any logged in user will be able to enter most part of the system
- { pattern: "/*", auth-mechanisms: ["basic","form"], exclude-patterns: ["/api/admin/*"] }
# Only administrators are allowed to access /api/admin/*
- { pattern: "/api/admin/*", auth-mechanisms: ["basic"], expected-roles: ["ADMIN"] }
TODO
If you opt to use the Fixed User and Password Identity Manager, you can set the expected username, password and role at server.auth.fixed-auth
entry of your configuration file. You can find the default values here.
server:
auth:
fixed-auth:
username: "admin"
password: "admin"
role: "admin"
Consider the bellow configuration.
server:
auth:
rules:
- { pattern: "/protected/*", auth-'mechanisms: ["form"] }
fixed-auth:
username: "admin"
password: "1q2w3e"
role: "admin"
endpoints:
login-page: "/auth/login.html"
error-page: "/auth/error.html"
permission-denied-page: "/auth/forbiden.html"
callback-url: "/auth/callback"
Here we've defined a set of configuration parameters related to Form Authentication. At the first block we which resources will be required authorization to access. Besides is impossible to set more than one Authentication Mechanism at once, we set only "form" to simplify our example.
As we defined the "default" identity-manager as our mechanism to validate the credentials sent by the HTTP client, we defined the username and password at the fixed-auth
block. The last block, form-auth
define which pages will be used during the authentication lifecycle:
<!-- http://www.avajava.com/tutorials/lessons/how-do-i-use-form-authentication-with-tomcat.html -->
<form method="POST" action="/protected/j_security_check">
<table>
<tr>
<td colspan="2">Login to the Demo application:</td>
</tr>
<tr>
<td>Name:</td>
<td><input type="text" name="j_username" /></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="j_password"/ ></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Go" /></td>
</tr>
</table>
</form>
Above a sample login.html
. Java developers will be at home here once it follows the same standard for form authentication defined by Servlet API:
WELCOME About Kikaha philosophy
GETTING STARTED Getting started in 1 minute Creating a Kikaha maven project Architecture overview
TUTORIALS Logging configuration Configuring the server Creating your first HTTP route Kikaha's command line interface Configuring your favorite IDE Wro4j Integration
CORE FEATURES HTTP and HTTPS Routing static assets Dependency injection Authentication and authorization Smart routes
ESSENTIAL MODULES μRouting API WebSocket Routing Database Connection Pool JSON with Jackson Protobuf Mustache Templates Rocker Templates BCrypt
CLOUD MODULES Overview of Cloud Modules Consul.io Codahale's Metrics Auth0 Single Sign-On μWorkers - Actor-like API Hazelcast
AWS-RELATED MODULES Overview of AWS-Related Modules Deploying Applications on AWS AWS IAM Credentials AWS EC2 AWS SQS queues AWS CloudWatch metrics AWS Application Load Balancer AWS Lambda functions AWS X-Ray
ADVANCED TOPICS Creating custom modules Routing with Undertow's API Creating custom cloud modules