WebCenters Portals REST API and WebCenter Content provide a great set of web services enabling you to create rich interactive JavaScript components.
An issue you may have come across if you don’t have SSO enabled is the ability to interact against these services. This can be a problem if you are writing Javascript Widgets or hybrid mobile applications for WebCenter Portal that require authentication to access them.
You could present a popup requesting the user to re authenticate; however this isn’t ideal if the user has already authenticated with the portal to access your new JS Components.
Read on to see the options available to you –
There are two options available if you don’t use SSO:
1) Enabling AJAX pre-authentication on the WebCenter portal login page; which will store the authenticated session.
2) Setting up a trust service token and passing the authentication request with the token when you need to access the services once the user has authenticated.
1. Pre-authenticating against the REST API.
1.1 Updating the login template for pre-auth.
On the login page disable the submit event on the form to authenticate against WebCenter Portal.
Instead when the user selects the login button –
1. Pass a base64 authentication request to the REST API via AJAX.
2. On a success response (store the REST API security token if needed)
3. Trigger the submit request to enable the form post to authenticate on WebCenter.
Here are some code samples for authenticating with either WebCenter Portal or Content via AJAX using JQuery –
WebCenter Portal AJAX REST API Authentication
(with OIT or Username & Password)
jquery.ajax({ url: endpoint, dataType: 'json', beforeSend: function(xhr) { //if trust token not defined send base64 user/pass authentication if (FB.restInfo.trustServiceToken === undefined) { //pass user/password credentials if (username.length > 0) { //IE has no support for BTOA use crypto lib if (window.btoa === undefined) { xhr.setRequestHeader('Authorization', 'Basic ' + Crypto.util.bytesToBase64(Crypto.charenc.Binary.stringToBytes(username + ':' + password))); //all other browsers support BTOA } else { xhr.setRequestHeader('Authorization', 'Basic ' + window.btoa(username+':'+password)); } return; } //else pass security token } else { //token auth xhr.setRequestHeader('Authorization', 'OIT ' + FB.restInfo.trustServiceToken); ///Obj path to Trust token value } //pass secure token xhr.withCredentials = true; }, //Authentication Successful success: function(data) { //Process Resource Index Object in callback method //Store REST API Token callback(context); }, //Authentication Failed error: function(request, status, error) { error_handler(callback)(request, status, error, endpoint); } });
WebCenter Content AJAX Authentication
(with OIT or Username & Password)
var params = { IdcService: 'PING_SERVER', IsJson: 1 }; //Authenticate with WebCenter Content jquery.ajax({ url: endpoint+ '/idcplg', data: params, dataType: 'json', //user already authenticated success: function(data) { callback(this); }, //Error connection or authorisation to WebCenter Content failed error: function(request, status, error) { //if trust token defined send OIT Auth Request if (FB.restInfo.trustServiceToken !== undefined) { //Authenticate Via OIT jquery.ajax({ type: "GET", url: '/adfAuthentication', //http://domain.com/adfAuthentication will auth OIT on WebCenter //setup request headers first beforeSend: function(xhr) { xhr.setRequestHeader('Authorization', 'OIT ' + FB.restInfo.trustServiceToken); //Obj path to Trust token value xhr.withCredentials = true; }, //request successfull success: function(data) { callback(this); }, //issue with request error: function(request, status, error) { error_handler(callback)(request, status, error, endpoint+ '/idcplg'); } }); //else user/pass sent } else { //Authenticate with user/pass jquery.ajax({ type: "POST", url: endpoint+'/login/j_security_check', data: { j_username: username, j_password: password, j_character_encoding: 'UTF-8' }, //request successfull success: function(data) { callback(this); }, //issue with request error: function(request, status, error) { error_handler(callback)(request, status, error, endpoint+ '/idcplg'); } }); } } });
The WebCenter Content Secure Token Auth requires authentication on http://domain.com/adfAuthentication.
You can also use this to authenticate against the Inbound Refinery (Conversion Server)
http://domain.com/ibr/adfAuthentication
And Universal Records Management
http://domain.com/urm/adfAuthentication
Where as User/Pass Auth on the content server is requested via http://domain.com/cs/login/j_security_check.
Here is a simple example of a webcenter login page that makes an Authentication request first to the REST API before posting the form and logging into WebCenter Portal.
<!DOCTYPE html> <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--> <!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--> <!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]--> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>Login Auth Example</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width"> </head> <body> <div id="FB-loginWrapper"> <h2>Sign-in to your account</h2> <form name="PortalLoginForm" method="post" action="/webcenter/wcAuthentication"> <input type="hidden" name="success_url" value="/webcenter/intranet_loginhandlerservlet"/> <input type="hidden" name="j_character_encoding" value="UTF-8"> <div class="formField"> <label>Username:</label> <input type="text" name="j_username" /> </div> <div class="formField"> <label>Password:</label> <input type="password" name="j_password" /> </div> <input disabled="disabled" type="submit" /> </form> </div> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script> <script src="js/vendor/cryptojs.js"></script> <script> //Setup JS namespace var FB = FB || {}; FB.Login = (function() { return { //on script init init: function() { //Setup page events this.events(); //remove disabled attr on submit button. $('[name="PortalLoginForm"] [type="submit"]').prop('disabled',false); }, //setup page events events: function() { //on submit click initialise auth request $('[name="PortalLoginForm"]').submit(function() { //if data attribute true on form allow submit if ($(this).data('valid')) { return true; } //call REST API authentication method FB.Login.AuthRestAPI( '/rest/api/resourceIndex', //endpoint $('[name="j_username"]').val(), //User $('[name="j_password"]').val(), //Pass function() { //callback method $('[name="PortalLoginForm"]').data('valid', true).submit(); //enable form to submit $('[name="PortalLoginForm"] [type="submit"]').submit(); //submit form on AuthRestAPI success AJAX. } ); //else stop form from submitting return false; }); }, //REST Auth AJAX method AuthRestAPI:function(endpoint, username, password, callback) { //make ajax req $.ajax({ url: endpoint, dataType: 'json', beforeSend: function(xhr) { //IE has no support for BTOA use cryptoJS lib if (window.btoa === undefined) { xhr.setRequestHeader('Authorization', 'Basic ' + Crypto.util.bytesToBase64(Crypto.charenc.Binary.stringToBytes(username + ':' + password))); //all other browsers support BTOA } else { xhr.setRequestHeader('Authorization', 'Basic ' + window.btoa(username+':'+password)); } //pass secure token xhr.withCredentials = true; }, //Authentication Successful success: function(data) { //submit form via callback callback(); }, //Authentication Failed error: function(request, status, error) { alert('Authentication failed'); } }); } } })(); //on DOM Loaded setup page $(document).ready(function() { FB.Login.init(); }); </script> </body> </html>
2. Setting up the the trust service security token
(Info to setup OIT).
I would recommend setting up the trust token; however the base64 authentication pre login above is easier and quicker to setup.
The trust token will be generated once the user has logged in.
2.1. Create keystore
a) cd /opt/oracle/jrmc-4.0.1-1.6.0/bin/
b) keytool -genkeypair -keyalg RSA -dname “cn=spaces,dc=domain,dc=com” -alias orakey -keypass myKeyPassword -keystore /opt/oracle/keystore/default-keystore.jks -storepass myKeyPassword -validity 1064
c) keytool -exportcert -v -alias orakey -keystore /opt/oracle/keystore/default-keystore.jks -storepass myKeyPassword -rfc -file /opt/oracle/keystore/orakey.cer
d) keytool -importcert -alias webcenter_spaces_ws -file /opt/oracle/keystore/orakey.cer -keystore /opt/oracle/keystore/default-keystore.jks -storepass myKeyPassword
2.2. Update jps-config.xml
a)
<serviceInstance name="keystore" provider="keystore.provider" location="/opt/oracle/keystore/default-keystore.jks"> <description>Default JPS Keystore Service</description>
b)
<propertySets> <propertySet name="trust.provider.embedded"> ... existing entries <property value="orakey" name="trust.aliasName"/> <property value="orakey" name="trust.issuerName"/> </propertySet> </propertySets>
2.3. Update credential store
a) in WLST: /opt/oracle/middleware/Oracle_WC1/common/bin/wlst.sh
b) connect()
c) updateCred(map=”oracle.wsm.security”, key=”keystore-csf-key”, user=”owsm”, password=”myKeyPassword “, desc=”Keystore key”)
d) updateCred(map=”oracle.wsm.security”, key=”enc-csf-key”, user=”orakey”, password=”myKeyPassword “, desc=”Encryption key”)
e) updateCred(map=”oracle.wsm.security”, key=”sign-csf-key”, user=”orakey”, password=”myKeyPassword “, desc=”Signing key”)
2.4. Add TrustServiceIdentityAsserter.
a) Console -> Security Realms -> myrealm -> Providers -> New
b) Restart all
2.5. Configure Credential Store
a) in WLST: /opt/oracle/middleware/Oracle_WC1/common/bin/wlst.sh
b) connect()
c) createCred(map=”o.webcenter.jf.csf.map”, key=”keygen.algorithm”,user=”keygen.algorithm”, password=”AES”)
d) createCred(map=”o.webcenter.jf.csf.map”, key=”cipher.transformation”,user=”cipher.transformation”, password=”AES/CBC/PKCS5Padding”)
2.6. Test it against the rest api
a) http://www.domain.com/rest/api/resourceIndex
Once setup create a bean to output the token into the page template ie ${fb_rtc_bean.trustServiceToken} JS object so that your JS AJAX request can reuse it.
var FB = FB || {}; FB.restInfo = { username: '${securityContext.userName}', trustServiceToken: '${fb_rtc_bean.trustServiceToken}', spaceName: '${spaceContext.currentSpaceName}', spaceGUID: '${spaceContext.currentSpace.metadata.guid}' };
You can then use one of the AJAX authentication methods above with ${fb_rtc_bean.trustServiceToken} reading the JS Obj FB.restInfo.trustServiceToken;