Introduction
This is a Ruby library to interface with the uuOpenIdConnect (uuOIDC) API. It is a part of uuAppServerKit used for development of uuApplications under the Unicorn Application Framework (UAF).
More information about OIDC Flows and internals can be found on http://openid.net/connect/
Requirements
This code has been run and tested on:
- MRI Ruby 2.2.1 on Linux platform - for production usage.
- MRI Ruby 2.2.1 on Windows 10 platform - for development (not production)
- JRuby9k may work, but is NOT TESTED, some restrictions are known as unsuported EC-Cryptography
The uu_oidc-server
with same or greater version than uu_oidc
client expected on server-side for full client functionality/features support.
</a>Installation
This package is available in uuGEMs Repository - https://gems.plus4u.net and can be installed with:
gem install uu_oidcg01 -s https://gems.plus4u.net
For users of bundler
:
Gemfile:
source 'https://gems.plus4u.net' do
gem 'uu_oidcg01', '~>4.2'
end
bundler install
API Documentation
The API documentation is provided here: uuOpenIdConnect Client API reference.
Example Usage
The following scenarios shows typical usage of the uuOIDC Client API for users and applications authentication.
- Client uuOIDC Session login with Resource Owner Password grant flow
- Client uuOIDC Session login with Authorization Code grant flow
- Server uuOIDC Session in uuApp Controller
- Call uuApp Controller with HTTPClient and uuOIDC Session
- Call uuApp Controller with uuApp Client and uuOIDC Session
- Call uu8 Command with HTTPClient and uuOIDC Session
- Call uu8 Command with UU_OS API and uuOIDC Session
The most important class for all scenarios is UuOidc::Session.
Before start
To try samples below some prerequisites are needed:
- installed uu_oidc gem - see Instalation
- for uu8 samples you must be a registered plus4u.net user
- default uuOIDC server provider is https://oidc.plus4u.net/uu-oidcg01-main/0-0
- for change the provider, use ENV to set default uri
- Windows:
set UU_OIDC_SERVER_URI=https://host:port/uu-oidcg01-main/0-0
- Linux:
export $UU_OIDC_SERVER_URI=https://host:port/uu-oidcg01-main/0-0
- Windows:
- on testing environment the SSL self-signed certificate could be tolerated, use ENV to disable certificate verification
- Windows:
set UU_OIDC_SSL_VERIFY_MODE=0
- Linux:
export $UU_OIDC_SSL_VERIFY_MODE=0
- Windows:
- for change the provider, use ENV to set default uri
Client uuOIDC Session login with ResourceOwnerPasswordGrantFlow
This scenario could be used for direct user login - when the application has access to user credentials
AccessCode1(username)and AccessCode2(password).
Typical usage is for uuEE authentication. This authentication could be executed on client (console, installed app, …)
and server-side (in uuApp Controller), where interaction with user is not possible.
Avoid this flow for use cases where the user interaction is possible, than prefer the Interactive Login with Browser scenario.
require 'uu_oidc' # Change to your user credentials CREDENTIALS = { access_code1: 'user_frog', access_code2: 'Frog2016Secret$' } ses=UuOidc::Session.login(CREDENTIALS) puts("Welcome: #{ses.identity}")
The credentials for login could be read from password file, configuration or some other kind of secured storage.
Always externalize the credentials from code, don´t put credentials into codebase (git) repository !!!.
Client uuOIDC Session login with AuthorizationCodeGrantFlow
Following samples shows the best practice for login on client side when user interaction is possible. It uses the most secured flow (AuthorizationCodeGrant), recommended by OpenIDConnect specification. The advantage of this solution lies in possibility to use full power of uuOIDC authentication: * federated login feature - single sign on with Google, Facebook, Microsoft, etc. * UI login page * Remember-Me login * When session already established, user is automatically logged (SingleSignOn with your session in browser) * No need to put, store etc. credentials on client, in code, in passwordfiles, in environment or on other place. Client has no access to your credentials, wow!
The principle of this flow is based on following steps: * Session prepares URI for uuOIDC server call for login * User must open the uuOIDC login URI in browser and follow instructions * when needed, user must sign-in with credentials to uuOIDC - independently on client application * uuOIDC server generates the unique AccessCode * User uses the AccessCode for client Session.login to obtain Session AccessToken from uuOIDC server.
Interactive Login with STD-OUT/-IN
This sample shows all steps for AuthorizationCodeGrantFlow.
It could be used in situations, when it is not possible to open Browser from Ruby.
require 'uu_oidc' uri = UuOidc::Session.get_access_token_grant_code_uri() puts 'Open following URI in browser and follow instructions to return back here with generated Access Token Code.' puts "Login URI: #{uri}" puts 'Enter your Access Token Code:' access_token_code = STDIN.gets.chomp ses = UuOidc::Session.login(code: access_token_code) puts "Welcome #{ses.identity[:name]}!"The better way how to login with interaction with user see the next sample: Interactive Login with Browser ### </a>Interactive Login with Browser This sample simplifies the interaction for user. The browser will be automatically opened with uuOIDC URI and HTTP-Callback server is temporary started for callback from uuOIDC server to accept the generated AccessCode. It is secure, standard solution with smart interaction for user.
require 'uu_oidc' ses = UuOidc::Session.loginInteractive() puts "Welcome #{ses.identity[:name]}!" ses = UuOidc::Session.loginInteractive(prompt: 'login') # force login prompt puts "Welcome #{ses.identity[:name]}!"
Server uuOIDC Session in uuApp Controller
This chapter shows some typical scenarios used on server-side in uuApp Controllers ### Access Session informations This sample shows access to Session on server side. It is simple uuApp Controller that uses
require 'uu_oidc' # This OIDCSampleController must be used with uuAppServer class OIDCSampleController def echo(ctrl_env) ses = ctrl_env.session() # obtain current oidc session dtoOut = {} dtoOut[:sid] = ses.sid() # access unique oidc session ID dtoOut[:identity] = ses.identity() # obtain info about User identity dtoOut[:client_app_identity] = ses.client_app_identity() # obtain info about dtoOut[:app_identity] = ses.app_identity() # info about current application dtoOut[:call_token] = ses.get_call_token() # generate token to call other apps ctrl_env.result = dtoOut end end
Force login from server side
There may be some use cases where the application needs to reassure itself that the authenticated user is already on client side - the login is fresh (max_login_age). Or the application needs to ensure that the authentication was processed with specific secure way - login_level_of_assurance.
require 'uu_oidc' # This OIDCSampleController must be used with uuAppServer class OIDCSampleController def echo(ctrl_env) ses = ctrl_env.session() # obtain current oidc session ses.ensure_login(ctrl_env, { login_level_of_assurance: [UuOidc::Session::OAUTH_ACR_LOA_1, UuOidc::Session::OAUTH_ACR_LOA_2, UuOidc::Session::OAUTH_ACR_LOA_3], max_login_age: 30 }) dtoOut = {} dtoOut[:sid] = ses.sid() # access unique oidc session ID dtoOut[:identity] = ses.identity() # obtain info about User identity dtoOut[:client_app_identity] = ses.client_app_identity() # obtain info about dtoOut[:app_identity] = ses.app_identity() # info about current application dtoOut[:call_token] = ses.get_call_token() # generate token to call other apps ctrl_env.result = dtoOut end end
Login as uuEE
You can use Session.login as on client side to login for some specific uuEE and call the remote command from controller as shown in this sample:
The uuEE credentials have to be externalized from source code !!!
require 'uu_oidc' # This OIDCSampleController must be used with uuAppServer class OIDCSampleController # should be externalized !!! password file, etc. UUEE_CREDENTIALS = { access_code1: 'uuee_ac1', access_code2: 'uuee_ac2' } CALL_URI = UuOidc::Discovery::Discovery.new().[:userinfo_endpoint] def echo(ctrl_env) ses=UuOidc::Session.login(CREDENTIALS) token = ses.get_call_token() # call some nested command via HTTP client client = HTTPClient.new(); resp = client.get(CALL_URI, header: { 'Authorization' => "Bearer #{token}", 'Accept' => 'application/json' }) dtoOut = {} dtoOut[:nested_call_status] = resp.status dtoOut[:nested_call_result] = resp.content ctrl_env.result = dtoOut end end
Call uuApp Controller with HTTPClient and uuOIDC Session
The operation Session.get_call_token() could be used to obtain secure token that should be used for remote call to uuAppServer.
Server call have to be requested with the standard HTTP “Authorization” header with “Bearer “ prefix for token in value.
require 'uu_oidc' # Change to your user credentials CREDENTIALS = { access_code1: 'user_frog', access_code2: 'Frog2016Secret$' } UU_APP_UC_URI = UuOidc::Discovery::Discovery.new().[:userinfo_endpoint] ses=UuOidc::Session.login(CREDENTIALS) token = ses.get_call_token() # call some command client = HTTPClient.new(); resp = client.get(UU_APP_UC_URI, header: { 'Authorization' => "Bearer #{token}", 'Accept' => 'application/json' }) puts("uuApp response: #{resp.status}, #{resp.content}")
Call uuApp Controller with uuApp Client and uuOIDC Session
For uuApp Client is prepared interceptor handler that adds the HTTP Authorization header to each remote call with token from specified session.
require 'uu_oidc' require 'uu_app_core-appclient' # Change to your user credentials CREDENTIALS = { access_code1: 'user_frog', access_code2: 'Frog2016Secret$' } UU_APP_UC_URI = UuOidc::Discovery::Discovery.new().[:userinfo_endpoint] ses=UuOidc::Session.login(CREDENTIALS) # call some command client = UuApp::AppClient::Client.new(); client.add_interceptor(UuOidc::AppSession::AppClientSessionHandler); result = client.get(UU_APP_UC_URI, { session: ses }); puts("Result: #{result}");
Call uu8 Command with HTTPClient and uuOIDC Session
The uu8 Command APIs supports integration with uuOIDC authentication and so the Session call token could be used for uu8 invocation.
require 'uu_oidc' # Change to your user credentials CREDENTIALS = { access_code1: 'user_frog', access_code2: 'Frog2016Secret$' } UU8_COMMAND_URI = 'https://api.plus4u.net/ues/wcp/ues/core/security/session/UESSession/getPersonalRole' ses=UuOidc::Session.login(CREDENTIALS); token = ses.get_call_token(); client = HTTPClient.new(); resp = client.get(UU8_COMMAND_URI, header: { 'Authorization' => "Bearer #{token}", 'Accept' => 'application/json' }); puts("UU8 Command response: #{resp.status}, #{resp.content}");
Call uu8 Command with UU_OS API and uuOIDC Session
The uu8 client libraries use uu8 Session internally, so for this scenarios the uuOIDC Call token have to be transformed to uu8 call token first.
require 'uu_os' require 'uu_oidc' # Change to your user credentials CREDENTIALS = { access_code1: 'user_frog', access_code2: 'Frog2016Secret$' } ses=UuOidc::Session.login(CREDENTIALS); token = ses.get_call_token(); # UU8 Commands API requires use of UU::OS:Session => use OIDC-Token as supported "HTTP authorization token" # https://api.plus4u.net/uuos/UU/OS/Security/Session.html#login-class_method UU::OS::Security::Session.login("Bearer #{token}"); person = UU::OS::Security::Session.get_personal_role(); puts("Welcome: #{person}");
Client uuOIDC Session login change options
Change default settings is sometimes needed for Session instance - like for testing or staging environments.
Use parameter options
for this. Next sample shows how to change OIDC server URI and disable SSL certificate verification.
require 'uu_oidc' ses=UuOidc::Session.login(access_code1: 'user_frog', access_code2: 'Frog2016Secret$', options:{uu_oidc_server_uri: 'https://oidc.plus4u.net/uu-oidcg01-main/84723967990075193-a763a18b17d44725b13e00d5f2ab7cef', uu_oidc_client_ssl_verify_mode:OpenSSL::SSL::VERIFY_NONE }) puts("Welcome: #{ses.identity}")
What next
Licence
The uuOpenIdConnect Client is under UAFL (Unicorn Application Framework Licence) derived from BSD.
(c) 2017 https://unicorn.com