Implementation of Tizen SSO APIs
authorImran Zaman <imran.zaman@intel.com>
Fri, 4 Jul 2014 11:24:35 +0000 (14:24 +0300)
committerImran Zaman <imran.zaman@intel.com>
Tue, 15 Jul 2014 20:39:31 +0000 (23:39 +0300)
23 files changed:
examples/index.html
examples/sso.html [new file with mode: 0644]
packaging/tizen-extensions-crosswalk.spec
sso/README.md [new file with mode: 0644]
sso/sso.gyp [new file with mode: 0644]
sso/sso_api.js [new file with mode: 0644]
sso/sso_async_op.cc [new file with mode: 0644]
sso/sso_async_op.h [new file with mode: 0644]
sso/sso_auth_service.cc [new file with mode: 0644]
sso/sso_auth_service.h [new file with mode: 0644]
sso/sso_auth_session.cc [new file with mode: 0644]
sso/sso_auth_session.h [new file with mode: 0644]
sso/sso_extension.cc [new file with mode: 0644]
sso/sso_extension.h [new file with mode: 0644]
sso/sso_identity.cc [new file with mode: 0644]
sso/sso_identity.h [new file with mode: 0644]
sso/sso_identity_info.cc [new file with mode: 0644]
sso/sso_identity_info.h [new file with mode: 0644]
sso/sso_instance.cc [new file with mode: 0644]
sso/sso_instance.h [new file with mode: 0644]
sso/sso_utils.cc [new file with mode: 0644]
sso/sso_utils.h [new file with mode: 0644]
tizen-wrt.gyp

index b569a4a..be7d8d2 100644 (file)
@@ -19,22 +19,23 @@ div.block {
 </head>
 <body>
 <h1>Tizen Extensions Crosswalk examples</h1>
-<a href="tizen.html"><div class="block">tizen top namespace</div></a>
-<a href="network_bearer_selection.html"><div class="block">network bearer selection</div></a>
-<a href="notification.html"><div class="block">notification</div></a>
-<a href="system_info.html"><div class="block">system info</div></a>
-<a href="system_setting.html"><div class="block">system setting</div></a>
-<a href="time.html"><div class="block">time</div></a>
-<a href="power.html"><div class="block">power</div></a>
+<a href="alarm.html"><div class="block">alarm</div></a>
+<a href="application.html"><div class="block">application</div></a>
+<a href="audiosystem.html"><div class="block">audiosystem</div></a>
 <a href="bluetooth.html"><div class="block">bluetooth</div></a>
+<a href="callhistory.html"><div class="block">Call History</div></a>
+<a href="content.html"><div class="block">content</div></a>
 <a href="download.html"><div class="block">download</div></a>
 <a href="filesystem.html"><div class="block">filesystem</div></a>
-<a href="application.html"><div class="block">application</div></a>
-<a href="callhistory.html"><div class="block">Call History</div></a>
 <a href="mediaserver.html"><div class="block">mediaserver</div></a>
-<a href="audiosystem.html"><div class="block">audiosystem</div></a>
-<a href="content.html"><div class="block">content</div></a>
+<a href="network_bearer_selection.html"><div class="block">network bearer selection</div></a>
+<a href="notification.html"><div class="block">notification</div></a>
+<a href="power.html"><div class="block">power</div></a>
 <a href="speech.html"><div class="block">speech</div></a>
-<a href="alarm.html"><div class="block">alarm</div></a>
+<a href="sso.html"><div class="block">SSO</div></a>
+<a href="system_info.html"><div class="block">system info</div></a>
+<a href="system_setting.html"><div class="block">system setting</div></a>
+<a href="time.html"><div class="block">time</div></a>
+<a href="tizen.html"><div class="block">tizen top namespace</div></a>
 </body>
 </html>
diff --git a/examples/sso.html b/examples/sso.html
new file mode 100644 (file)
index 0000000..74ba2e8
--- /dev/null
@@ -0,0 +1,513 @@
+<html>
+<head>
+<title>SSO example</title>
+</head>
+<body>
+<style type="text/css">
+  .topleftcorner {
+    position:relative;
+    width: 33%;
+  }
+  .toprightcorner {
+    position:absolute;
+    top:0;
+    right:0;
+    width: 33%;
+  }
+  .topcenter {
+    position: absolute;
+    width: 100%;
+    left: 100%;
+    top: 0%;
+    height:100%
+  }
+</style>
+
+<div id='serviceContainer' class="topleftcorner">
+<table id="service" border="5">
+  <tr>
+    <th colspan="2">
+      <H3><BR>Service</H3>
+    </th>
+  </tr>
+    <th>API</th>
+    <th>Arg1</th>
+  <tr><td><button onclick='queryMethods()'>Query Methods</button></td></tr>
+  <tr><td><button onclick='queryMechanisms()'>Query Mechanisms</button></td>
+    <td><form>Method: <input type="text" name="serv_method" id="serv_method"><br></form></td>
+  </tr>
+  <tr><td><button onclick='queryIdentities()'>Query Identities</button></td>
+  <td><form>Filter(key1:val1,key2:val2,...):
+      <input type="text" name="serv_filter" id="serv_filter"><br></form></td>
+  </tr>
+  <tr><td><button onclick='getIdentity()'>Get Identity</button></td>
+    <td><form>Id: <input type="text" name="serv_identityid" id="serv_identityid"><br></form></td>
+  </tr>
+  <tr><td><button onclick='clearDB()'>Clear DB</button></td></tr>
+</table>
+
+<table id="creat_identity" border="5">
+  <tr>
+    <th colspan="1">
+      <H3><button onclick='onCreateIdentity()'><BR>Create Identity</button>
+        <button onclick='onUpdateIdentity()'><BR>Update Identity</button></H3>
+    </th>
+  </tr>
+  <tr><td><form>Select Type: <select name="cident_type" id="cident_type">
+    <option value = "APP" >Application</option>
+    <option value = "WEB" selected >Web</option>
+    <option value = "NET" >Network</option>
+    </select></form></td></tr>
+  <tr><td><form>Username: 
+    <input type="text" name="cident_username" id="cident_username"><br></form></td></tr>
+  <tr><td><form>Password: 
+    <input type="text" name="cident_secret" id="cident_secret"><br></form></td></tr>
+  <tr><td><form>StoreSecret: 
+    <input type="checkbox" name="cident_storesecret" id="cident_storesecret"><br></form></td></tr>
+  <tr><td><form>Caption: 
+    <input type="text" name="cident_caption" id="cident_caption"><br></form></td></tr>
+  <tr><td><form>Realms(realm1,realm2,..): 
+    <input type="text" name="cident_realms" id="cident_realms"><br></form></td></tr>
+  <tr><td><form>Owner(appcontext,syscontext): 
+    <input type="text" name="cident_owner" id="cident_owner"><br></form></td></tr>
+  <tr><td><form>ACL(json:  [{"secContext":{"sysContext":"*","appContext":"*"}, 
+    "method":"password","mechanisms":["password"]}]): 
+    <input type="text" name="cident_acl" id="cident_acl"><br></form></td></tr>
+</table>
+<div id='resultContainer' class="topcenter">>
+<form name='form_out'>
+  <textarea name="form_text" id="form_text" style="width:100%; height:100%"></textarea>
+</form>
+</div>
+
+</div>
+
+<div id='identityContainer' class="toprightcorner">
+<table width="115%" id="identity" border="5">
+  <tr>
+    <th colspan="2">
+      <H3><BR>Identity</H3>
+      <form>Selected Identity JSId: 
+        <select name="ident_options" id="ident_options" onchange="onIdentityChanged(this)">
+        </select></form>
+    </th>
+  </tr>
+    <th>API</th>
+    <th>Arg1</th>
+  <tr><td><button onclick='startSession()'>Start Session</button></td>
+    <td><form>Method: <input type="text" name="ident_method" id="ident_method"><br></form></td>
+  </tr>
+  <tr><td><button onclick='requestCredentialsUpdate()'>Update Credentials</button></td>
+    <td><form>Message: <input type="text" name="ident_message" id="ident_message"><br></form></td>
+  </tr>
+  <tr><td><button onclick='store(null)'>Store</button></td>
+  </tr>
+  <tr><td><button onclick='addReference()'>Add Reference</button></td>
+    <td><form>Reference: <input type="text" name="ident_addref" id="ident_addref"><br></form></td>
+  </tr>
+  <tr><td><button onclick='removeReference()'>Remove Reference</button></td>
+    <td><form>Reference: <input type="text" name="ident_remref" id="ident_remref"><br></form></td>
+  </tr>
+  <tr><td><button onclick='removeIdentity()'>Remove</button></td>
+  </tr>
+  <tr><td><button onclick='signout()'>Signout</button></td>
+  </tr>
+</table>
+
+<table id="session" border="5">
+  <tr>
+    <th colspan="3">
+      <H3><BR>Session</H3>
+      <form>Selected Session JSId: <select name="sess_options" id="sess_options"></select></form>
+    </th>
+  </tr>
+    <th>API</th>
+    <th>Arg1</th>
+    <th>Arg2</th>
+  <tr><td><button onclick='queryAvailableMechanisms()'>QueryAvailableMechanisms</button></td>
+    <td><form>WantedMechanisms(mech1,mech2,..): 
+      <input type="text" name="sess_mechs" id="sess_mechs"><br></form></td>
+  </tr>
+  <tr><td><button onclick='challenge()'>Challenge</button></td>
+    <td><form>Mechanism: <input type="text" name="sess_mech" id="sess_mech"><br></form></td>
+    <td><form>SessionData (json: {"key1":"value1","key2":"value2",...}): 
+      <input type="text" name="sess_data" id="sess_data"><br></form></td>
+  </tr>
+  <tr><td><button onclick='cancel()'>Cancel</button></td>
+  </tr>
+</table>
+</div>
+
+<script>
+
+function _logData(data) {
+  var old = document.form_out.form_text.value
+  document.form_out.form_text.value = data + '\n\n' + old;
+}
+
+function queryMethods() {
+  tizen.sso.authService.queryMethods().then(function(result) {
+    _logData('QueryMethods successful: ' + JSON.stringify(result));},
+    function (err) { document.form_out.form_text.value += "\n" + "QueryMethods failed: " + err;});
+}
+
+function queryMechanisms() {
+  var method = document.getElementById('serv_method').value;
+  tizen.sso.authService.queryMechanisms(method).then(function (result) {
+    _logData('QueryMechanisms successful: ' + JSON.stringify(result));},
+    function(err) {_logData('QueryMechanisms failed: ' + err);});
+}
+
+function queryIdentities() {
+  var str = document.getElementById('serv_filter').value;
+  var filters = {};
+  if (typeof str === 'string' && str.length > 0) {
+    var ufilter = str.split(",");  
+    for (var i = 0; i < ufilter.length; i++) {
+      var keyval = ufilter[i].split(":");
+      filters[keyval[0]] = keyval[1];
+    }
+  }
+  tizen.sso.authService.queryIdentities(filters).then(onQueryIdentitiesComplete, function(err) {
+    _logData('QueryIdentities failed: ' + err);});
+}
+
+function onQueryIdentitiesComplete(result) {
+  _logData('QueryIdentities successful: ' + JSON.stringify(result));
+}
+
+function getIdentity() {
+  var id = parseFloat(document.getElementById('serv_identityid').value);
+  if (id == NaN) {
+    _logData('Invalid id');
+    return;
+  }
+  var res = tizen.sso.authService.getIdentity(id);
+  if (res != null)
+    res.then(onGetIdentityComplete, function(err) {
+        _logData('GetIdentity failed: ' + err);});
+  else
+    _logData('Identity not found with the specified id');  
+}
+
+function onGetIdentityComplete(result) {
+  _logData('GetIdentity successful: ' + JSON.stringify(result));
+}
+
+function clearDB() {
+  tizen.sso.authService.clear().then(function(result) {
+    _logData('Clear successful: ' + JSON.stringify(result));
+    clearSelect(document.getElementById("ident_options"));
+    clearSelect(document.getElementById("sess_options"));},
+    function(err) {_logData('Clear failed: ' + err);});
+}
+
+function getInfo() {
+  var owner = {};
+  var str = document.getElementById('cident_owner').value;
+  if (typeof str === 'string' && str.length > 0) {
+    arr = str.split(",");
+    if (arr.length == 2) {
+      owner.sysContext = arr[0];
+      owner.appContext = arr[1];
+    }    
+  }
+  var realms = [];
+  str = document.getElementById('cident_realms').value;
+  if (typeof str === 'string' && str.length > 0) {
+    arr = str.split(",");
+    if (arr.length > 0) realms = arr;
+  }
+  var acl = [{}];
+  str = document.getElementById('cident_acl').value;
+  if (typeof str === 'string' && str.length > 0) {
+    acl = JSON.parse(str);
+  }
+  var info = {
+    'type': document.getElementById('cident_type').value,
+    'username': document.getElementById('cident_username').value,
+    'secret': document.getElementById('cident_secret').value, 
+    'storeSecret': document.getElementById('cident_storesecret').checked, 
+    'caption': document.getElementById('cident_caption').value, 
+    'realms': realms, 
+    'owner': owner, 
+    'accessControlList': acl  
+  };
+  return info;
+}
+
+function onCreateIdentity() {
+  var info = getInfo();
+  var res = tizen.sso.authService.createIdentity(info);
+  if (res.syncOpErrorMsg != null) {
+    _logData('Identity creation FAILED with error: ' + res.asyncOpErrorMsg);
+    return;
+  }
+  
+  identityAdded(res.identity);
+  _logData('Identity is added with jsid: ' + res.identity.jsid);
+}
+
+function onUpdateIdentity() {
+  var info = getInfo();
+  store(info);
+}
+
+function identityAdded(ident) {
+  var select = document.getElementById("ident_options");
+  var option = document.createElement('option');
+  option.text = option.value = ident.jsid;
+  select.add(option, 0);
+
+  ident.onsignedout = function (ident) {
+    _logData('Identity with id ' + ident.info.id + ' is signedout and jsid is '
+      + ident.jsid);};
+  ident.onremoved = onIdentityRemoved;
+}
+
+function onIdentityRemoved(ident) {
+  _logData('Identity with id ' + ident.info.id + ' is removed and its jsid is '
+    + ident.jsid);
+  if (document.getElementById('ident_options').value == ident.jsid) {
+    for (var i = 0; i < ident.sessions.length; i++) {
+      var sessionobj = ident.sessions[i];
+      sessionobj.removeEventListener('statechanged', onSessionStateChanged);
+      document.getElementById('sess_options').remove(i);
+    }
+    clearSelectOption(document.getElementById("ident_options"), ident.jsid);
+  }
+}
+
+function clearSelectOption(element, value) {
+  for (var i=0; i<element.length; i++) {
+    if (element.options[i].value == value) 
+       element.remove(i);
+  }
+}
+
+function clearSelect(element) {
+  for (var i=0; i<element.length; i++) {
+    element.remove(i);
+  }
+}
+
+function onIdentityChanged(select) {
+  var jsid = document.getElementById("ident_options").value;
+  _logData('Identity selected with jsid: ' + jsid);
+  var identobj = tizen.sso.authService.getIdentityByJSId(jsid);
+  if (identobj == null) {
+    _logData('identity NOT found');
+    return;
+  }
+  clearSelect(document.getElementById("sess_options"));
+  for (var i = 0; i < identobj.sessions.length; i++) {
+    var option = document.createElement('option');
+    option.text = option.value = identobj.sessions[i].jsid;
+    document.getElementById('sess_options').add(option, 0);
+  }
+}
+
+//identity interface
+function startSession() {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  var method = document.getElementById('ident_method').value;
+  
+  identobj.startSession(method).then(onStartSessionComplete,
+    function(err) {_logData('startSession failed: ' + err);});
+}
+
+function onStartSessionComplete(sessionobj) {
+  _logData('startSession successful: ' + JSON.stringify(sessionobj));
+  sessionobj.addEventListener('statechanged', onSessionStateChanged);
+
+  _logData('Session with jsid as ' + sessionobj.jsid + ' is added for identity with jsid '
+     + sessionobj.identityJSId);
+  var select = document.getElementById("ident_options");
+  if (select.value == sessionobj.identityJSId) {
+    var sess_select = document.getElementById("sess_options");
+    var option = document.createElement('option');
+    option.text = option.value = sessionobj.jsid;
+    sess_select.add(option, 0);
+  }
+}
+
+function onSessionStateChanged(event) {
+  var sessionobj = event.session;
+  _logData('Session with jsid ' + sessionobj.jsid + ' state has changed to '
+    + sessionobj.sessionState);
+}
+
+function requestCredentialsUpdate() {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  var message = document.getElementById('ident_message').value;
+  
+  identobj.requestCredentialsUpdate(message).then(function(msg) {
+    document.form_out.form_text.value += "\n" + "requestCredentialsUpdate succeeded";},
+    function(err) {_logData('requestCredentialsUpdate failed: ' + err);});
+}
+
+function store(info) {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  if (info != null) identobj.updateInfo(info);
+
+  identobj.store().then(function(msg) {
+    _logData('store succeeded with resp: ' + JSON.stringify(msg));},
+    function(err) {_logData('store failed: ' + err);});
+}
+
+function addReference() {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  var reference = document.getElementById('ident_addref').value;
+  
+  identobj.addReference(reference).then(function(msg) {
+    _logData('addReference succeeded');},
+    function(err) {_logData('addReference failed: ' + err);});
+}
+
+function removeReference() {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  var reference = document.getElementById('ident_remref').value;
+  
+  identobj.removeReference(reference).then(function(msg) {
+    _logData('removeReference succeeded');},
+    function(err) {_logData('removeReference failed: ' + err);});
+}
+
+function removeIdentity() {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  identobj.remove().then(onIdentityRemoved,
+    function(err) {_logData('remove failed: ' + err);});
+}
+
+function signout() {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  identobj.signout().then(function(msg) {
+    _logData('signout succeeded');},
+    function(err) {_logData('signout failed: ' + err);});
+}
+
+//authsession interface
+function queryAvailableMechanisms() {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  var sessionobj = identobj.getSessionByJSId(document.getElementById('sess_options').value);
+  if (sessionobj == null) {
+    _logData('session NOT selected/found. Please select/create session first');
+    return;
+  }
+  _logData('session found with JSId: ' + sessionobj.jsid);
+
+  var str = document.getElementById('sess_mechs').value;
+  var wantedMechs = [];
+  if (typeof str === 'string' && str.length > 0) {
+      arr = str.split(",");
+      if (arr.length > 0) wantedMechs  = arr;
+  }
+  sessionobj.queryAvailableMechanisms(wantedMechs).then(function(msg) {
+    _logData('queryAvailableMechanisms succeeded with mechanisms:' + JSON.stringify(msg));},
+    function(err) {_logData('queryAvailableMechanisms failed: ' + err);});
+}
+
+function challenge() {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  var sessionobj = identobj.getSessionByJSId(document.getElementById('sess_options').value);
+  if (sessionobj == null) {
+    _logData('session NOT selected/found. Please select/create session first');
+    return;
+  }
+  _logData('session found with JSId: ' + sessionobj.jsid);
+
+  var mech = document.getElementById('sess_mech').value;
+  var sessionData = document.getElementById('sess_data').value;
+  
+  sessionobj.challenge(mech, sessionData).then(function(msg) {
+    _logData('challenge succeeded with sessionData: ' + JSON.stringify(msg));},
+    function(err) {_logData('challenge failed: ' + err);});
+}
+
+function cancel() {
+  var identobj = tizen.sso.authService.getIdentityByJSId(
+    document.getElementById('ident_options').value);
+  if (identobj == null) {
+    _logData('identity NOT selected/found. Please select/create an identity first');
+    return;
+  }
+  _logData('identity found with JSId: ' + identobj.jsid);
+  var sessionobj = identobj.getSessionByJSId(document.getElementById('sess_options').value);
+  if (sessionobj == null) {
+    _logData('session NOT selected/found. Please select/create session first');
+    return;
+  }
+  _logData('session found with JSId: ' + sessionobj.jsid);
+
+  sessionobj.removeEventListener('statechanged', onSessionStateChanged);
+  sessionobj.cancel().then(function(msg) {
+    _logData('cancel succeeded');},
+    function(err) {_logData('cancel failed: ' + err);});
+  clearSelectOption(document.getElementById('sess_options'), sessionobj.jsid);
+}
+
+window.onload = function() {
+  document.getElementById('cident_acl').value =
+    JSON.stringify([{"secContext":{"sysContext":"*","appContext":"*"},
+    "method":"password","mechanisms":["password"]}]);
+  document.getElementById('cident_owner').value = "*,*";
+};
+
+</script>
+
+</body>
+</html>
index 45e7418..5319925 100644 (file)
@@ -55,14 +55,15 @@ BuildRequires: pkgconfig(dbus-glib-1)
 BuildRequires: pkgconfig(evas)
 BuildRequires: pkgconfig(gio-2.0)
 BuildRequires: pkgconfig(glib-2.0)
-BuildRequires: pkgconfig(tapi)
-BuildRequires: pkgconfig(libudev)
+BuildRequires: pkgconfig(libgsignon-glib)
 BuildRequires: pkgconfig(libpulse) >= 5.0
+BuildRequires: pkgconfig(libudev)
 BuildRequires: pkgconfig(message-port)
 BuildRequires: pkgconfig(notification)
 BuildRequires: pkgconfig(pkgmgr)
 BuildRequires: pkgconfig(pkgmgr-info)
 BuildRequires: pkgconfig(pmapi)
+BuildRequires: pkgconfig(tapi)
 BuildRequires: pkgconfig(vconf)
 %if %{with wayland}
 BuildRequires: pkgconfig(wayland-client)
diff --git a/sso/README.md b/sso/README.md
new file mode 100644 (file)
index 0000000..ef273e3
--- /dev/null
@@ -0,0 +1,6 @@
+## Introduction
+This folder contains implementation of Web Single Signon API for Crosswalk runtime.
+API specification can be located at https://code.google.com/p/accounts-sso/source/browse/widl/signon.widl?repo=libgsignon-glib
+
+Backend that provides core functionality is gSSO and more information about that
+component could be found at https://01.org/gsso
\ No newline at end of file
diff --git a/sso/sso.gyp b/sso/sso.gyp
new file mode 100644 (file)
index 0000000..50b3072
--- /dev/null
@@ -0,0 +1,38 @@
+{
+  'includes':[
+    '../common/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'tizen_sso',
+      'type': 'loadable_module',
+      'variables': {
+        'packages': [
+          'libgsignon-glib',
+        ],
+      },
+      'includes': [
+        '../common/pkg-config.gypi',
+      ],
+      'sources': [
+        'sso_api.js',
+        'sso_async_op.cc',
+        'sso_async_op.h',
+        'sso_auth_service.cc',
+        'sso_auth_service.h',
+        'sso_auth_session.cc',
+        'sso_auth_session.h',
+        'sso_extension.cc',
+        'sso_extension.h',
+        'sso_identity.cc',
+        'sso_identity.h',
+        'sso_identity_info.cc',
+        'sso_identity_info.h',
+        'sso_instance.cc',
+        'sso_instance.h',
+        'sso_utils.cc',
+        'sso_utils.h',
+      ],
+    },
+  ],
+}
diff --git a/sso/sso_api.js b/sso/sso_api.js
new file mode 100644 (file)
index 0000000..17d112a
--- /dev/null
@@ -0,0 +1,600 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+///////////////////////////////////////////////////////////////////////////////
+// Utilities
+///////////////////////////////////////////////////////////////////////////////
+
+var g_next_async_call_id = 0;
+var g_async_calls = {};
+var g_next_obj_id = 0;
+
+function AsyncCall(resolve, reject, command) {
+  this.resolve = resolve;
+  this.reject = reject;
+  this.command = command;
+}
+
+function _createPromise(msg) {
+  var promise = new Promise(function(resolve, reject) {
+    g_async_calls[g_next_async_call_id] = new AsyncCall(resolve, reject,
+        msg.asyncOpCmd);
+  });
+  msg.asyncOpId = g_next_async_call_id;
+  extension.postMessage(JSON.stringify(msg));
+  ++g_next_async_call_id;
+  return promise;
+}
+
+function _sendSyncMessage(msg) {
+  return JSON.parse(extension.internal.sendSyncMessage(JSON.stringify(msg)));
+}
+
+function _isCommandInProgress(command) {
+  for (var key in g_async_calls) {
+    if (g_async_calls.hasOwnProperty(key) &&
+        g_async_calls[key].command == command) {
+      return true;
+    }
+  }
+  return false;
+}
+
+function _addConstProperty(obj, propertyKey, propertyValue) {
+  Object.defineProperty(obj, propertyKey, {
+    configurable: true,
+    enumerable: true,
+    writable: false,
+    value: propertyValue
+  });
+}
+
+function _addConstPropertyFromObject(obj, propertyKey, propObject) {
+  if (!propObject.hasOwnProperty(propertyKey))
+    return;
+  Object.defineProperty(obj, propertyKey, {
+    configurable: false,
+    enumerable: true,
+    writable: false,
+    value: propObject[propertyKey]});
+}
+
+function _addPropertyFromObject(obj, propertyKey, propObject) {
+  if (!propObject.hasOwnProperty(propertyKey))
+    return;
+  Object.defineProperty(obj, propertyKey, {
+    configurable: false,
+    enumerable: true,
+    writable: true,
+    value: propObject[propertyKey]});
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Enumerations and dictionaries
+///////////////////////////////////////////////////////////////////////////////
+
+var IdentityType = {
+  APPLICATION: 0,
+  WEB: 1,
+  NETWORK: 2
+};
+
+var SessionState = {
+  NOT_STARTED: 0,
+  RESOLVING_HOST: 1,
+  CONNECTING: 2,
+  SENDING_DATA: 3,
+  WAITING_REPLY: 4,
+  USER_PENDING: 5,
+  UI_REFRESHING: 6,
+  PROCESS_PENDING: 7,
+  STARTED: 8,
+  PROCESS_CANCELLING: 9,
+  PROCESS_DONE: 10,
+  CUSTOM: 11
+};
+
+var UserPromptPolicy = {
+  DEFAULT: 0,
+  REQUEST_PASSWORD: 1,
+  NO_USER_INTERACTION: 2,
+  VALIDATION: 3
+};
+
+function MechanismQueryResult(obj) {
+  _addConstPropertyFromObject(this, 'method', obj);
+  _addConstPropertyFromObject(this, 'mechanisms', obj);
+}
+
+function IdentityInfo(obj) {
+  _addConstPropertyFromObject(this, 'id', obj);
+  _addConstProperty(this, 'type', _convertToIdentityType(obj.type));
+  _addPropertyFromObject(this, 'username', obj);
+  _addPropertyFromObject(this, 'caption', obj);
+  _addPropertyFromObject(this, 'secret', obj);
+  _addPropertyFromObject(this, 'storeSecret', obj);
+  _addPropertyFromObject(this, 'realms', obj);
+  _addConstPropertyFromObject(this, 'owner', obj);
+  _addPropertyFromObject(this, 'accessControlList', obj);
+}
+
+function _destroyIdentity(ident) {
+  var msg = {
+    'asyncOpCmd': 'destroyIdentity',
+    'serviceJSId': g_auth_service.jsid,
+    'identityJSId': ident.jsid
+  };
+  return _createPromise(msg);
+}
+
+function _getSessionObj(sessionJSId) {
+  var sessobj = null;
+  if (sessionJSId == -1) return null;
+  for (var i = 0; i < g_identities.length; i++) {
+    var identity = g_identities[i];
+    for (var j = 0; j < identity.sessions.length; j++) {
+      var sess = identity.sessions[j];
+      if (sess.jsid == sessionJSId) {
+        sessobj = sess;
+        break;
+      }
+    }
+  }
+  return sessobj;
+}
+
+function _getIdentityObj(id) {
+  if (id == -1) return null;
+  var identobj = null;
+  for (var i = 0; i < g_identities.length; i++) {
+    var curr_ident = g_identities[i];
+    if (curr_ident.info.id == id) {
+      identobj = curr_ident;
+      break;
+    }
+  }
+  return identobj;
+}
+
+function _getIdentityObjByJSId(jsid) {
+  if (jsid == -1) return null;
+  var identobj = null;
+  for (var i = 0; i < g_identities.length; i++) {
+    var curr_ident = g_identities[i];
+    if (curr_ident.jsid == jsid) {
+      identobj = curr_ident;
+      break;
+    }
+  }
+  return identobj;
+}
+
+function _convertToIdentityType(stringtype) {
+  if (stringtype == 'APPLICATION') return IdentityType.APPLICATION;
+  else if (stringtype == 'WEB') return IdentityType.WEB;
+  else if (stringtype == 'NETWORK') return IdentityType.NETWORK;
+  else return IdentityType.WEB;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Extension msg listener and utility functions
+///////////////////////////////////////////////////////////////////////////////
+var g_identities = [];
+var g_auth_service = new AuthService();
+exports.authService = g_auth_service;
+
+var g_auth_session_listeners = {};
+g_auth_session_listeners['statechanged'] = [];
+
+extension.setMessageListener(function(json) {
+  var msg = JSON.parse(json);
+  if (msg.asyncOpErrorMsg != null) {
+    handleAsyncCallError(msg);
+    return;
+  }
+
+  if (msg.asyncOpCmd != null) {
+    switch (msg.asyncOpCmd) {
+      case 'queryMethods':
+      case 'queryMechanisms':
+      case 'queryIdentities':
+      case 'clear':
+      case 'destroyIdentity':
+      case 'requestCredentialsUpdate':
+      case 'addReference':
+      case 'removeReference':
+      case 'verifyUser':
+      case 'verifyUserPrompt':
+      case 'signout':
+      case 'cancel':
+        handleAsyncCallSuccess(msg);
+        break;
+      case 'getIdentity':
+        handleGetIdentity(msg);
+        break;
+      case 'startSession':
+        handleStartSession(msg);
+        break;
+      case 'store':
+        handleStore(msg);
+        break;
+      case 'remove':
+        handleRemoveIdentity(msg);
+        break;
+      case 'queryAvailableMechanisms':
+        handleQueryAvailableMechanisms(msg);
+        break;
+      case 'challenge':
+        handleChallenge(msg);
+        break;
+      default:
+        handleAsyncCallError(msg);
+        break;
+    }
+  } else if (msg.info != null) {
+    switch (msg.info.info) {
+      case 'signedout':
+        var identobj = g_auth_service.getIdentityByJSId(msg.objectJSId);
+        if (identobj != null && identobj.onsignedout) identobj.onsignedout(identobj);
+        break;
+      case 'removed':
+        if (_isCommandInProgress('remove'))
+          break;
+        var identobj = g_auth_service.getIdentityByJSId(msg.objectJSId);
+        if (identobj != null) {
+          if (identobj.onremoved) identobj.onremoved(identobj);
+          g_identities.splice(g_identities.indexOf(identobj), 1);
+          _destroyIdentity(identobj);
+        }
+        break;
+      case 'sessionStateChanged':
+        handleSessionStateChanged(msg);
+        break;
+      default:
+        console.log('Unknown signal received: ' + JSON.stringify(msg));
+        break;
+    }
+  }
+});
+
+function handleAsyncCallSuccess(msg) {
+  g_async_calls[msg.asyncOpId].resolve(msg.responseData);
+  delete g_async_calls[msg.asyncOpId];
+}
+
+function handleAsyncCallError(msg) {
+  if (msg.asyncOpCmd == 'getIdentity') {
+    var identobj = g_auth_service.getIdentityByJSId(
+        msg.responseData.identityJSId);
+    if (identobj != null)
+      g_identities.splice(g_identities.indexOf(identobj), 1);
+  }
+  g_async_calls[msg.asyncOpId].reject(Error(msg.asyncOpErrorMsg));
+  delete g_async_calls[msg.asyncOpId];
+}
+
+function handleGetIdentity(msg) {
+  var identobj = _getIdentityObjByJSId(msg.responseData.identityJSId);
+  if (identobj) {
+    identobj.info = new IdentityInfo(msg.responseData.info);
+    g_async_calls[msg.asyncOpId].resolve(identobj);
+  } else {
+    g_async_calls[msg.asyncOpId].reject(Error('Identity object not found for getidentity'));
+  }
+  delete g_async_calls[msg.asyncOpId];
+}
+
+function handleStartSession(msg) {
+  var identobj = g_auth_service.getIdentityByJSId(msg.objectJSId);
+  if (identobj) {
+    var session = new AuthSession(msg.responseData, msg.objectJSId);
+    identobj.sessions.push(session);
+    g_async_calls[msg.asyncOpId].resolve(session);
+  } else {
+    g_async_calls[msg.asyncOpId].reject(Error('Identity object not found for session'));
+  }
+  delete g_async_calls[msg.asyncOpId];
+}
+
+function handleStore(msg) {
+  var identobj = g_auth_service.getIdentityByJSId(msg.objectJSId);
+  if (identobj != null) {
+    identobj.info.id = msg.responseData.identityId;
+    g_async_calls[msg.asyncOpId].resolve(identobj);
+  } else {
+    g_async_calls[msg.asyncOpId].reject(Error('Identity NOT FOUND'));
+  }
+  delete g_async_calls[msg.asyncOpId];
+}
+
+function handleRemoveIdentity(msg) {
+  var identobj = g_auth_service.getIdentityByJSId(msg.objectJSId);
+  if (identobj != null) {
+    g_async_calls[msg.asyncOpId].resolve(identobj);
+    g_identities.splice(g_identities.indexOf(identobj), 1);
+  } else {
+    g_async_calls[msg.asyncOpId].reject(Error('Identity NOT FOUND'));
+  }
+  delete g_async_calls[msg.asyncOpId];
+}
+
+function handleSessionStateChanged(msg) {
+  var session = _getSessionObj(msg.objectJSId);
+  if (session == null) return;
+
+  var event = new CustomEvent('statechanged');
+  session.sessionState = msg.info.object.sessionState;
+  _addConstProperty(event, 'session', session);
+  if (msg.message) _addConstProperty(event, 'message', msg.message);
+  session.dispatchEvent(event);
+  if (session.onstatechanged)
+    session.onstatechanged(event);
+}
+
+function handleQueryAvailableMechanisms(msg) {
+  g_async_calls[msg.asyncOpId].resolve(msg.responseData.mechanisms);
+  delete g_async_calls[msg.asyncOpId];
+}
+
+function handleChallenge(msg) {
+  g_async_calls[msg.asyncOpId].resolve(msg.responseData.sessionData);
+  delete g_async_calls[msg.asyncOpId];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// AuthService
+///////////////////////////////////////////////////////////////////////////////
+
+function AuthService() {
+  this.jsid = ++g_next_obj_id;
+}
+
+AuthService.prototype.queryMethods = function() {
+  var msg = {
+    'asyncOpCmd': 'queryMethods',
+    'serviceJSId': this.jsid
+  };
+  return _createPromise(msg);
+};
+
+AuthService.prototype.queryMechanisms = function(method) {
+  var msg = {
+    'asyncOpCmd': 'queryMechanisms',
+    'serviceJSId': this.jsid,
+    'method': method
+  };
+  return _createPromise(msg);
+};
+
+AuthService.prototype.queryIdentities = function(filter) {
+  var msg = {
+    'asyncOpCmd': 'queryIdentities',
+    'serviceJSId': this.jsid,
+    'filter': filter
+  };
+  return _createPromise(msg);
+};
+
+AuthService.prototype.getIdentity = function(identity_id) {
+  var identobj = _getIdentityObj(identity_id);
+  if (identobj == null) {
+    identobj = new Identity(null);
+    g_identities.push(identobj);
+  }
+  var msg = {
+    'asyncOpCmd': 'getIdentity',
+    'serviceJSId': this.jsid,
+    'identityId': identity_id,
+    'identityJSId': identobj.jsid
+  };
+  return _createPromise(msg);
+};
+
+AuthService.prototype.getIdentityByJSId = function(jsid) {
+  return _getIdentityObjByJSId(jsid);
+};
+
+AuthService.prototype.createIdentity = function(info) {
+  var identobj = new Identity(new IdentityInfo(info));
+  var msg = {
+    'syncOpCmd': 'createIdentity',
+    'serviceJSId': this.jsid,
+    'identityJSId': identobj.jsid
+  };
+  var res = _sendSyncMessage(msg);
+  if (res.syncOpErrorMsg != null) {
+    return res;
+  }
+  g_identities.push(identobj);
+  res.identity = identobj;
+  return res;
+};
+
+AuthService.prototype.clear = function() {
+  var msg = {
+    'asyncOpCmd': 'clear',
+    'serviceJSId': this.jsid
+  };
+  return _createPromise(msg);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Identity
+///////////////////////////////////////////////////////////////////////////////
+function Identity(info) {
+  this.onsignedout = null;
+  this.onremoved = null;
+  this.info = info;
+  this.sessions = [];
+  this.jsid = ++g_next_obj_id;
+}
+
+Identity.prototype.startSession = function(method) {
+  var msg = {
+    'asyncOpCmd': 'startSession',
+    'identityJSId': this.jsid,
+    'sessionJSId': ++g_next_obj_id,
+    'method': method
+  };
+  return _createPromise(msg);
+};
+
+Identity.prototype.getSessionByJSId = function(jsid) {
+  if (jsid == -1) return null;
+  var sessobj = null;
+  for (var i = 0; i < this.sessions.length; i++) {
+    var sess = this.sessions[i];
+    if (sess.jsid == jsid) {
+      sessobj = sess;
+      break;
+    }
+  }
+  return sessobj;
+};
+
+Identity.prototype.requestCredentialsUpdate = function(message) {
+  var msg = {
+    'asyncOpCmd': 'requestCredentialsUpdate',
+    'identityJSId': this.jsid,
+    'message': message
+  };
+  return _createPromise(msg);
+};
+
+Identity.prototype.store = function() {
+  var msg = {
+    'asyncOpCmd': 'store',
+    'identityJSId': this.jsid,
+    'info': this.info
+  };
+  return _createPromise(msg);
+};
+
+Identity.prototype.addReference = function(reference) {
+  var msg = {
+    'asyncOpCmd': 'addReference',
+    'identityJSId': this.jsid,
+    'reference': reference
+  };
+  return _createPromise(msg);
+};
+
+Identity.prototype.removeReference = function(reference) {
+  var msg = {
+    'asyncOpCmd': 'removeReference',
+    'identityJSId': this.jsid,
+    'reference': reference
+  };
+  return _createPromise(msg);
+};
+
+Identity.prototype.verifyUser = function(message) {
+  var msg = {
+    'asyncOpCmd': 'verifyUser',
+    'identityJSId': this.jsid,
+    'message': message
+  };
+  return _createPromise(msg);
+};
+
+Identity.prototype.verifyUserPrompt = function(params) {
+  var msg = {
+    'asyncOpCmd': 'verifyUserPrompt',
+    'identityJSId': this.jsid,
+    'params': params
+  };
+  return _createPromise(msg);
+};
+
+Identity.prototype.remove = function() {
+  var msg = {
+    'asyncOpCmd': 'remove',
+    'identityJSId': this.jsid
+  };
+  return _createPromise(msg);
+};
+
+Identity.prototype.signout = function() {
+  var msg = {
+    'asyncOpCmd': 'signout',
+    'identityJSId': this.jsid
+  };
+  return _createPromise(msg);
+};
+
+Identity.prototype.updateInfo = function(info) {
+  var old = this.info;
+  this.info = new IdentityInfo(info);
+  if (old != null)
+    this.info.id = old.id;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// AuthSession
+///////////////////////////////////////////////////////////////////////////////
+function AuthSession(obj, identity_jsid) {
+  _addConstProperty(this, 'jsid', obj.sessionJSId);
+  _addConstProperty(this, 'identityJSId', identity_jsid);
+  _addConstPropertyFromObject(this, 'method', obj);
+  _addPropertyFromObject(this, 'sessionState', obj);
+  this.onstatechanged = null;
+}
+
+function isValidType(type) {
+  return (type === 'statechanged');
+}
+
+AuthSession.prototype.addEventListener = function(type, callback) {
+  if (callback != null && isValidType(type)) {
+    if (g_auth_session_listeners[type].indexOf(callback) != -1)
+      g_auth_session_listeners[type].push(callback);
+  }
+};
+
+AuthSession.prototype.removeEventListener = function(type, callback) {
+  if (callback != null && isValidType(type)) {
+    var index = g_auth_session_listeners[type].indexOf(callback);
+    if (index >= 0)
+      g_auth_session_listeners[type].splice(index, 1);
+  }
+};
+
+AuthSession.prototype.dispatchEvent = function(event) {
+  var handled = true;
+  if (typeof event !== 'object' || !isValidType(event.type))
+    return false;
+
+  g_auth_session_listeners[event.type].forEach(function(callback) {
+    var res = callback(event);
+    if (!res && handled) handled = false;
+  });
+  return handled;
+};
+
+AuthSession.prototype.queryAvailableMechanisms = function(wantedMechanisms) {
+  var msg = {
+    'asyncOpCmd': 'queryAvailableMechanisms',
+    'sessionJSId': this.jsid,
+    'wantedMechanisms': wantedMechanisms
+  };
+  return _createPromise(msg);
+};
+
+AuthSession.prototype.challenge = function(mechanism, sessionData) {
+  var msg = {
+    'asyncOpCmd': 'challenge',
+    'sessionJSId': this.jsid,
+    'mechanism': mechanism,
+    'sessionData': sessionData
+  };
+  return _createPromise(msg);
+};
+
+AuthSession.prototype.cancel = function() {
+  var msg = {
+    'asyncOpCmd': 'cancel',
+    'sessionJSId': this.jsid
+  };
+  return _createPromise(msg);
+};
diff --git a/sso/sso_async_op.cc b/sso/sso_async_op.cc
new file mode 100644 (file)
index 0000000..705c66d
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sso/sso_async_op.h"
+
+#include "common/extension.h"
+
+SSOAsyncOp::SSOAsyncOp(common::Instance* instance,
+    picojson::value* request_data, gpointer user_data)
+    : instance_(instance), request_data_(request_data), user_data_(user_data) {
+}
+
+SSOAsyncOp::~SSOAsyncOp() {
+  if (request_data_)
+    delete request_data_;
+  request_data_ = NULL;
+}
+
+void SSOAsyncOp::PostInfo(const picojson::value& info, int jsid) {
+  picojson::value::object object;
+  object["info"] = info;
+  object["objectJSId"] = picojson::value(static_cast<double>(jsid));
+  picojson::value value(object);
+  instance_->PostMessage(value.serialize().c_str());
+}
+
+void SSOAsyncOp::PostResult(const picojson::value& response, int jsid) {
+  picojson::value::object object;
+  object["asyncOpCmd"] = picojson::value(GetCommand());
+  object["asyncOpId"] = picojson::value(GetId());
+  object["objectJSId"] = picojson::value(static_cast<double>(jsid));
+  object["responseData"] = response;
+  picojson::value value(object);
+  instance_->PostMessage(value.serialize().c_str());
+}
+
+void SSOAsyncOp::PostResult(int jsid) {
+  picojson::value::object object;
+  object["asyncOpCmd"] = picojson::value(GetCommand());
+  object["asyncOpId"] = picojson::value(GetId());
+  object["objectJSId"] = picojson::value(static_cast<double>(jsid));
+  picojson::value value(object);
+  instance_->PostMessage(value.serialize().c_str());
+}
+
+void SSOAsyncOp::PostError(const gchar* error, int jsid) {
+  picojson::value::object object;
+  object["asyncOpCmd"] = picojson::value(GetCommand());
+  object["asyncOpId"] = picojson::value(GetId());
+  object["asyncOpErrorMsg"] = picojson::value(error);
+  object["objectJSId"] = picojson::value(static_cast<double>(jsid));
+  picojson::value value(object);
+  instance_->PostMessage(value.serialize().c_str());
+}
+
+void SSOAsyncOp::PostError(const gchar* error, const picojson::value& response,
+    int jsid) {
+  picojson::value::object object;
+  object["asyncOpCmd"] = picojson::value(GetCommand());
+  object["asyncOpId"] = picojson::value(GetId());
+  object["asyncOpErrorMsg"] = picojson::value(error);
+  object["objectJSId"] = picojson::value(static_cast<double>(jsid));
+  object["responseData"] = response;
+  picojson::value value(object);
+  instance_->PostMessage(value.serialize().c_str());
+}
+
+double SSOAsyncOp::GetId() const {
+  if (!request_data_)
+    return -1;
+  return request_data_->get("asyncOpId").get<double>();
+}
+
+std::string SSOAsyncOp::GetCommand() const {
+  if (!request_data_)
+    return std::string("Unknown");
+  return request_data_->get("asyncOpCmd").get<std::string>();
+}
diff --git a/sso/sso_async_op.h b/sso/sso_async_op.h
new file mode 100644 (file)
index 0000000..48cd11a
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SSO_SSO_ASYNC_OP_H_
+#define SSO_SSO_ASYNC_OP_H_
+
+#include <glib.h>
+
+#include <string>
+
+#include "common/picojson.h"
+#include "common/utils.h"
+
+namespace common {
+
+class Instance;
+
+}  // namespace common
+
+class SSOAsyncOp {
+ public:
+  SSOAsyncOp(common::Instance* instance, picojson::value* request_data,
+      gpointer user_data);
+  virtual ~SSOAsyncOp();
+
+  void PostInfo(const picojson::value& info, int jsid);
+  void PostResult(const picojson::value& response, int jsid);
+  void PostResult(int jsid);
+  void PostError(const gchar* error, int jsid);
+  void PostError(const gchar* error, const picojson::value& response, int jsid);
+
+  picojson::value* request_data() const { return request_data_; }
+  gpointer user_data() const { return user_data_; }
+
+ private:
+  picojson::value* request_data_;
+  common::Instance* instance_;
+  gpointer user_data_;
+
+  double GetId() const;
+  std::string GetCommand() const;
+
+  DISALLOW_COPY_AND_ASSIGN(SSOAsyncOp);
+};
+
+#endif  // SSO_SSO_ASYNC_OP_H_
diff --git a/sso/sso_auth_service.cc b/sso/sso_auth_service.cc
new file mode 100644 (file)
index 0000000..da962a5
--- /dev/null
@@ -0,0 +1,256 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sso/sso_auth_service.h"
+
+#include <libgsignon-glib/signon-identity.h>
+#include <stdlib.h>
+#include <string>
+
+#include "common/picojson.h"
+#include "sso/sso_async_op.h"
+#include "sso/sso_instance.h"
+#include "sso/sso_utils.h"
+
+MechanismQueryResult::MechanismQueryResult(const std::string& method,
+    const gchar* const* mechs)
+    : method_(method) {
+  if (mechs) {
+    while (*mechs)
+      mechanisms_.push_back(*mechs++);
+  }
+}
+
+MechanismQueryResult::~MechanismQueryResult() {
+}
+
+void MechanismQueryResult::FromJSON(const picojson::value& value) {
+  if (value.contains("method"))
+    method_ = value.get("method").to_str();
+  if (value.contains("mechanisms"))
+    mechanisms_ = SSOUtils::FromJSONArrayToStringVector(
+        value.get("mechanisms").get<picojson::array>());
+}
+
+picojson::value MechanismQueryResult::ToJSON() const {
+  picojson::value::object object;
+  if (!method_.empty())
+    object["method"] = picojson::value(method_);
+  if (!mechanisms_.empty())
+    object["mechanisms"] = picojson::value(
+        SSOUtils::FromStringVectorToJSONArray(mechanisms_));
+  return picojson::value(object);
+}
+
+bool MechanismQueryResult::ContainsData() const {
+  return (!method_.empty() || !mechanisms_.empty());
+}
+
+void SSOAuthService::QueryMethodsCb(SignonAuthService* auth_service,
+    gchar** methods, const GError* error, gpointer user_data) {
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOAuthService* service = reinterpret_cast<SSOAuthService*>(
+      async_op->user_data());
+  if (error) {
+    async_op->PostError(error->message, service->jsid());
+    delete async_op;
+    return;
+  }
+  picojson::value::object resp;
+  resp["methods"] = picojson::value(SSOUtils::FromStringArrayToJSONArray(
+      reinterpret_cast<const gchar* const*>(methods)));
+  g_strfreev(methods);
+  async_op->PostResult(picojson::value(resp), service->jsid());
+  delete async_op;
+}
+
+void SSOAuthService::QueryMechanismsCb(SignonAuthService* auth_service,
+    const gchar* method, gchar** mechanisms, const GError* error,
+    gpointer user_data) {
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOAuthService* service = reinterpret_cast<SSOAuthService*>(
+      async_op->user_data());
+  if (error) {
+    async_op->PostError(error->message, service->jsid());
+    delete async_op;
+    return;
+  }
+  MechanismQueryResult query_result(
+      async_op->request_data()->get("method").get<std::string>(),
+      reinterpret_cast<const gchar* const*>(mechanisms));
+  if (mechanisms)
+    g_strfreev(mechanisms);
+
+  async_op->PostResult(query_result.ToJSON(), service->jsid());
+  delete async_op;
+}
+
+void SSOAuthService::QueryIdentitiesCb(SignonAuthService* auth_service,
+    SignonIdentityList* identity_list, const GError* error,
+    gpointer user_data) {
+  GList* iter = identity_list;
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOAuthService* service = reinterpret_cast<SSOAuthService*>(
+      async_op->user_data());
+  if (error) {
+    async_op->PostError(error->message, service->jsid());
+    delete async_op;
+    return;
+  }
+  picojson::array infos;
+  while (iter) {
+    SignonIdentityInfo* info = static_cast<SignonIdentityInfo*>(iter->data);
+    SSOIdentityInfo identity_info(info);
+    infos.push_back(identity_info.ToJSON());
+    iter = g_list_next(iter);
+  }
+  g_list_free_full(identity_list, (GDestroyNotify) signon_identity_info_free);
+
+  async_op->PostResult(picojson::value(infos), service->jsid());
+  delete async_op;
+}
+
+void SSOAuthService::GetIdentityCb(SignonIdentity* identity,
+    SignonIdentityInfo* info, const GError* error, gpointer user_data) {
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOAuthService* service = reinterpret_cast<SSOAuthService*>(
+      async_op->user_data());
+  if (error) {
+    picojson::value::object resp;
+    resp["identityJSId"] = async_op->request_data()->get("identityJSId");
+    async_op->PostError(error->message, picojson::value(resp), service->jsid());
+    delete async_op;
+    return;
+  }
+  SSOIdentityPtr id_ptr = service->AddIdentity(identity,
+      static_cast<int>(async_op->request_data()->get(
+          "identityJSId").get<double>()), signon_identity_info_get_id(info));
+  SSOIdentityInfo id_info(info);
+  picojson::value::object resp;
+  resp["identityJSId"] = async_op->request_data()->get("identityJSId");
+  resp["info"] = id_info.ToJSON();
+  async_op->PostResult(picojson::value(resp), service->jsid());
+  delete async_op;
+}
+
+void SSOAuthService::ClearCb(SignonAuthService* auth_service, gboolean success,
+    const GError* error, gpointer user_data) {
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOAuthService* service = reinterpret_cast<SSOAuthService*>(
+      async_op->user_data());
+  if (error) {
+    async_op->PostError(error->message, service->jsid());
+    delete async_op;
+    return;
+  }
+  picojson::value::object resp;
+  resp["success"] = picojson::value(static_cast<bool>(success));
+  async_op->PostResult(picojson::value(resp), service->jsid());
+  delete async_op;
+}
+
+SSOAuthService::SSOAuthService(common::Instance* instance,
+    const std::string& appcontext)
+    : instance_(instance), auth_service_(0), jsid_(-1),
+      appcontext_(appcontext) {
+  auth_service_ = signon_auth_service_new();
+}
+
+SSOAuthService::~SSOAuthService() {
+  if (auth_service_) {
+    g_object_unref(auth_service_);
+    auth_service_ = 0;
+  }
+}
+
+void SSOAuthService::HandleQueryMethods(const picojson::value& value) {
+  signon_auth_service_query_methods(auth_service_,
+      &SSOAuthService::QueryMethodsCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOAuthService::HandleQueryMechanisms(const picojson::value& value) {
+  signon_auth_service_query_mechanisms(auth_service_,
+      reinterpret_cast<const gchar*>(value.get("method").to_str().c_str()),
+      &SSOAuthService::QueryMechanismsCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOAuthService::HandleQueryIdentities(const picojson::value& value) {
+  GHashTable* filters = IdentityFilterItem::FromJSONValueArray(
+      value.get("filter").get<picojson::object>());
+  signon_auth_service_query_identities(auth_service_, filters,
+      reinterpret_cast<const gchar*>(appcontext_.c_str()),
+      &SSOAuthService::QueryIdentitiesCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+  if (filters)
+    g_hash_table_unref(filters);
+}
+
+void SSOAuthService::HandleGetIdentity(const picojson::value& value) {
+  double id = value.get("identityId").get<double>();
+  SignonIdentity* identity = signon_identity_new_with_context_from_db(
+      static_cast<gint>(id),
+      reinterpret_cast<const gchar*>(appcontext_.c_str()));
+  signon_identity_query_info(identity, &SSOAuthService::GetIdentityCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOAuthService::HandleCreateIdentity(const picojson::value& value) {
+  SignonIdentity* identity = signon_identity_new_with_context(
+      reinterpret_cast<const gchar*>(appcontext_.c_str()));
+  AddIdentity(identity,
+      static_cast<int>(value.get("identityJSId").get<double>()), 0);
+}
+
+void SSOAuthService::HandleDestroyIdentity(const picojson::value& value) {
+  identities_.erase(static_cast<int>(value.get("identityJSId").get<double>()));
+}
+
+void SSOAuthService::HandleClear(const picojson::value& value) {
+  signon_auth_service_clear(auth_service_, &SSOAuthService::ClearCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+SSOIdentityPtr SSOAuthService::AddIdentity(SignonIdentity* identity, int jsid,
+    int identity_id) {
+  std::map<int, SSOIdentityPtr>::const_iterator it = identities_.find(jsid);
+  if (it != identities_.end())
+    return it->second;
+
+  SSOIdentityPtr identity_ptr;
+  if (identity_id != 0) {
+    for (it = identities_.begin(); it != identities_.end(); ++it) {
+      SSOIdentityPtr ptr = it->second;
+      if (identity_id == ptr->identity_id()) {
+        identity_ptr = ptr;
+        break;
+      }
+    }
+  }
+  if (!identity_ptr) {
+    identity_ptr = std::make_shared<SSOIdentity>(instance_, identity,
+        identity_id, jsid);
+  }
+  identities_.insert(std::make_pair(jsid, identity_ptr));
+  return identity_ptr;
+}
+
+SSOIdentityPtr SSOAuthService::GetIdentityPtr(int jsid) const {
+  SSOIdentityPtr identity_ptr;
+  std::map<int, SSOIdentityPtr>::const_iterator it = identities_.find(jsid);
+  if (it != identities_.end())
+    identity_ptr = it->second;
+  return identity_ptr;
+}
+
+SSOAuthSessionPtr SSOAuthService::GetAuthSessionPtr(int jsid) const {
+  std::map<int, SSOIdentityPtr>::const_iterator it;
+  for (it = identities_.begin(); it != identities_.end(); ++it) {
+    SSOAuthSessionPtr ptr = it->second->GetAuthSessionPtr(jsid);
+    if (ptr)
+      return ptr;
+  }
+  return SSOAuthSessionPtr();
+}
diff --git a/sso/sso_auth_service.h b/sso/sso_auth_service.h
new file mode 100644 (file)
index 0000000..016c651
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SSO_SSO_AUTH_SERVICE_H_
+#define SSO_SSO_AUTH_SERVICE_H_
+
+#include <libgsignon-glib/signon-auth-service.h>
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "sso/sso_auth_session.h"
+#include "sso/sso_identity.h"
+#include "sso/sso_utils.h"
+
+namespace common {
+
+class Instance;
+
+}  // namespace common
+
+namespace picojson {
+
+class value;
+
+}  // namespace picojson
+
+class MechanismQueryResult {
+ public:
+  MechanismQueryResult(const std::string& method, const gchar* const* mechs);
+  ~MechanismQueryResult();
+
+  void FromJSON(const picojson::value& value);
+  picojson::value ToJSON() const;
+  bool ContainsData() const;
+
+ private:
+  std::string method_;
+  std::vector<std::string> mechanisms_;
+};
+
+class SSOAuthService {
+ public:
+  SSOAuthService(common::Instance* instance, const std::string& appcontext);
+  virtual ~SSOAuthService();
+
+  int jsid() const { return jsid_; }
+  void set_jsid(int id) { jsid_ = id; }
+  const std::string& appcontext() const { return appcontext_; }
+
+  void HandleQueryMethods(const picojson::value& value);
+  void HandleQueryMechanisms(const picojson::value& value);
+  void HandleQueryIdentities(const picojson::value& value);
+  void HandleGetIdentity(const picojson::value& value);
+  void HandleCreateIdentity(const picojson::value& value);
+  void HandleDestroyIdentity(const picojson::value& value);
+  void HandleStartSession(const picojson::value& value);
+  void HandleClear(const picojson::value& value);
+
+  SSOIdentityPtr GetIdentityPtr(int jsid) const;
+  SSOAuthSessionPtr GetAuthSessionPtr(int jsid) const;
+
+ private:
+  static void QueryMethodsCb(SignonAuthService* auth_service, gchar** methods,
+      const GError* error, gpointer user_data);
+  static void QueryMechanismsCb(SignonAuthService* auth_service,
+      const gchar* method, gchar** mechanisms, const GError* error,
+      gpointer user_data);
+  static void QueryIdentitiesCb(SignonAuthService* auth_service,
+      SignonIdentityList* identity_list, const GError* error,
+      gpointer user_data);
+  static void GetIdentityCb(SignonIdentity* identity, SignonIdentityInfo* info,
+      const GError* error, gpointer user_data);
+  static void ClearCb(SignonAuthService* auth_service, gboolean success,
+      const GError* error, gpointer user_data);
+  SSOIdentityPtr AddIdentity(SignonIdentity* identity, int jsid, int id);
+
+ private:
+  common::Instance* instance_;
+  SignonAuthService* auth_service_;
+  std::map<int, SSOIdentityPtr> identities_;
+  int jsid_;
+  std::string appcontext_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSOAuthService);
+};
+
+#endif  // SSO_SSO_AUTH_SERVICE_H_
diff --git a/sso/sso_auth_session.cc b/sso/sso_auth_session.cc
new file mode 100644 (file)
index 0000000..875a2c0
--- /dev/null
@@ -0,0 +1,312 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sso/sso_auth_session.h"
+
+#include "sso/sso_async_op.h"
+#include "sso/sso_instance.h"
+#include "sso/sso_utils.h"
+
+SessionData::SessionData()
+    : data_(0) {
+  data_ = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+      signon_gvalue_free);
+}
+
+SessionData::~SessionData() {
+  if (data_) {
+    g_hash_table_unref(data_);
+    data_ = NULL;
+  }
+}
+
+bool SessionData::IsSupportedType(GType type) const {
+  return (signon_gtype_to_variant_type(type) != 0);
+}
+
+void SessionData::ToJSONType(picojson::object& object, const gchar* key,
+    GValue* value) const {
+  GType type = G_VALUE_TYPE(value);
+  if (!IsSupportedType(type))
+    return;
+
+  switch (type) {
+    case G_TYPE_STRING: {
+      std::string str = g_value_get_string(value);
+      if (!str.empty())
+        object[std::string(key)] = picojson::value(str);
+      break;
+    }
+    case G_TYPE_BOOLEAN: {
+      object[std::string(key)] = picojson::value(
+          static_cast<bool>(g_value_get_boolean(value)));
+      break;
+    }
+    case G_TYPE_UCHAR: {
+      object[std::string(key)] = picojson::value(
+          static_cast<double>(g_value_get_uchar(value)));
+      break;
+    }
+    case G_TYPE_INT: {
+      object[std::string(key)] = picojson::value(
+          static_cast<double>(g_value_get_int(value)));
+      break;
+    }
+    case G_TYPE_UINT: {
+      object[std::string(key)] = picojson::value(
+          static_cast<double>(g_value_get_uint(value)));
+      break;
+    }
+    case G_TYPE_INT64: {
+      object[std::string(key)] = picojson::value(
+          static_cast<double>(g_value_get_int64(value)));
+      break;
+    }
+    case G_TYPE_UINT64: {
+      object[std::string(key)] = picojson::value(
+          static_cast<double>(g_value_get_uint64(value)));
+      break;
+    }
+    case G_TYPE_DOUBLE: {
+      object[std::string(key)] = picojson::value(g_value_get_double(value));
+      break;
+    }
+    default:
+      if (type == G_TYPE_STRV) {
+        GVariant* var = g_value_get_variant(value);
+        const gchar** strv = g_variant_get_strv(var, 0);
+        if (strv) {
+          object[std::string(key)] = picojson::value(
+              SSOUtils::FromStringArrayToJSONArray(
+                  reinterpret_cast<const gchar* const*>(strv)));
+        }
+      }
+      break;
+  }
+}
+
+void SessionData::InsertStringData(const std::string& key,
+    const picojson::value& obj) {
+  GValue* val = g_new0(GValue, 1);
+  g_value_init(val, G_TYPE_STRING);
+  g_value_set_string(val, obj.get(key).to_str().c_str());
+  g_hash_table_insert(data_, g_strdup(key.c_str()), val);
+}
+
+void SessionData::InsertData(const std::string& key,
+    const picojson::value& obj) {
+  GValue* val = NULL;
+  if (obj.is<bool>()) {
+    val = g_new0(GValue, 1);
+    g_value_init(val, G_TYPE_BOOLEAN);
+    g_value_set_boolean(val, (gboolean) obj.get("renewToken").get<bool>());
+    g_hash_table_insert(data_, g_strdup(key.c_str()), val);
+  } else if (obj.is<std::string>()) {
+    val = g_new0(GValue, 1);
+    g_value_init(val, G_TYPE_STRING);
+    g_value_set_string(val, obj.to_str().c_str());
+    g_hash_table_insert(data_, g_strdup(key.c_str()), val);
+  } else if (obj.is<double>()) {
+    val = g_new0(GValue, 1);
+    g_value_init(val, G_TYPE_INT);
+    g_value_set_int(val, (gint) obj.get<double>());
+    g_hash_table_insert(data_, g_strdup(key.c_str()), val);
+  } else if (obj.is<picojson::array>() && IsSupportedType(G_TYPE_STRV)) {
+    val = g_new0(GValue, 1);
+    g_value_init(val, G_TYPE_STRV);
+    gchar** strv = SSOUtils::FromJSONArrayToStringArray(
+        obj.get<picojson::array>());
+    GVariant* var = g_variant_new_strv(strv, -1);
+    g_strfreev(strv);
+    g_value_set_variant(val, var);
+    g_hash_table_insert(data_, g_strdup(key.c_str()), val);
+  }
+}
+
+bool SessionData::InsertKnownData(const std::string& key,
+    const picojson::value& obj) {
+  bool inserted = true;
+  GValue* val = NULL;
+  if (key == "username" ||
+      key == "secret" ||
+      key == "realm" ||
+      key == "networkProxy" ||
+      key == "caption") {
+    InsertStringData(key, obj);
+  } else if (key == "networkTimeout") {
+    val = g_new0(GValue, 1);
+    g_value_init(val, G_TYPE_UINT);
+    g_value_set_uint(val, (guint) obj.get("networkTimeout").get<double>());
+    g_hash_table_insert(data_, g_strdup(key.c_str()), val);
+  } else if (key == "renewToken") {
+    val = g_new0(GValue, 1);
+    g_value_init(val, G_TYPE_BOOLEAN);
+    g_value_set_boolean(val, (gboolean) obj.get("renewToken").get<bool>());
+    g_hash_table_insert(data_, g_strdup(key.c_str()), val);
+  } else if (key == "userPromptPolicy") {
+    val = g_new0(GValue, 1);
+    g_value_init(val, G_TYPE_UINT);
+    g_value_set_uint(val, (guint) obj.get("userPromptPolicy").get<double>());
+    g_hash_table_insert(data_, g_strdup(key.c_str()), val);
+  } else if (key == "window_id") {
+    val = g_new0(GValue, 1);
+    g_value_init(val, G_TYPE_INT);
+    g_value_set_int(val, (gint) obj.get("window_id").get<double>());
+    g_hash_table_insert(data_, g_strdup(key.c_str()), val);
+  } else {
+    inserted = false;
+  }
+  return inserted;
+}
+
+void SessionData::FromJSON(const picojson::value& value) {
+  if (!value.is<picojson::object>())
+    return;
+
+  const picojson::object& obj = value.get<picojson::object>();
+  picojson::object::const_iterator it;
+  for (it = obj.begin(); it != obj.end(); ++it) {
+    std::string key = it->first;
+    picojson::value val = it->second;
+    if (!InsertKnownData(key, val)) {
+      InsertData(key, val);
+    }
+  }
+}
+
+picojson::value SessionData::ToJSON() const {
+  GHashTableIter iter;
+  g_hash_table_iter_init(&iter, data_);
+
+  char* key = NULL;
+  GValue* value = NULL;
+  picojson::value::object object;
+  while (g_hash_table_iter_next(&iter, reinterpret_cast<gpointer*>(&key),
+      reinterpret_cast<gpointer*>(&value))) {
+    ToJSONType(object, key, value);
+  }
+  return picojson::value(object);
+}
+
+GVariant* SessionData::ToVariant() const {
+  return signon_hash_table_to_variant(data_);
+}
+
+void SessionData::FromVariant(GVariant* vdata) {
+  if (data_) {
+    g_hash_table_unref(data_);
+    data_ = NULL;
+  }
+  data_ = signon_hash_table_from_variant(vdata);
+}
+
+void SSOAuthSession::QueryAvailableMechanismsCb(SignonAuthSession* self,
+    gchar** mechanisms, const GError* error, gpointer user_data) {
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOAuthSession* session = reinterpret_cast<SSOAuthSession*>(
+      async_op->user_data());
+  if (error) {
+    async_op->PostError(error->message, session->jsid_);
+    delete async_op;
+    return;
+  }
+
+  picojson::value::object resp;
+  resp["mechanisms"] = picojson::value(SSOUtils::FromStringArrayToJSONArray(
+      reinterpret_cast<const gchar* const*>(mechanisms)));
+  g_strfreev(mechanisms);
+
+  async_op->PostResult(picojson::value(resp), session->jsid_);
+  delete async_op;
+}
+
+void SSOAuthSession::ChallengeCb(GObject* source_object, GAsyncResult* res,
+    gpointer user_data) {
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOAuthSession* session = reinterpret_cast<SSOAuthSession*>(
+      async_op->user_data());
+
+  GError* error = NULL;
+  SignonAuthSession* auth_session = SIGNON_AUTH_SESSION(source_object);
+  GVariant* v_reply = signon_auth_session_process_finish(auth_session, res,
+      &error);
+  if (error) {
+    async_op->PostError(error->message, session->jsid_);
+    delete async_op;
+    g_error_free(error);
+    return;
+  }
+
+  SessionData data;
+  data.FromVariant(v_reply);
+  g_variant_unref(v_reply);
+  picojson::value::object resp;
+  resp["sessionData"] = picojson::value(data.ToJSON());
+  async_op->PostResult(picojson::value(resp), session->jsid_);
+  delete async_op;
+}
+
+void SSOAuthSession::StateChangeCb(SignonAuthSession* self, gint state,
+    gchar* message, gpointer user_data) {
+  SSOAuthSession* session = reinterpret_cast<SSOAuthSession*>(user_data);
+  SSOAsyncOp op(session->instance_, 0, session);
+  session->session_state_ = static_cast<SessionState>(state);
+  picojson::value::object info;
+  info["info"] = picojson::value("sessionStateChanged");
+  if (message)
+    info["message"] = picojson::value(std::string(message));
+  info["object"] = session->ToJSON();
+  op.PostInfo(picojson::value(info), session->jsid_);
+}
+
+SSOAuthSession::SSOAuthSession(common::Instance* instance,
+    SignonAuthSession* session, const std::string& method, int jsid)
+    : instance_(instance), session_(session), method_(method),
+      session_state_(SESSION_STATE_NOT_STARTED), jsid_(jsid) {
+  if (session_) {
+    g_signal_connect(session_, "state-changed",
+        G_CALLBACK(&SSOAuthSession::StateChangeCb), this);
+  }
+}
+
+SSOAuthSession::~SSOAuthSession() {
+  if (session_) {
+    g_object_unref(session_);
+    session_ = NULL;
+  }
+}
+
+void SSOAuthSession::HandleQueryAvailableMechanisms(
+    const picojson::value& value) {
+  gchar** mechs = SSOUtils::FromJSONArrayToStringArray(
+      value.get("wantedMechanisms").get<picojson::array>());
+  signon_auth_session_query_available_mechanisms(session_,
+      const_cast<const gchar**>(mechs),
+      &SSOAuthSession::QueryAvailableMechanismsCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+  g_strfreev(mechs);
+}
+
+void SSOAuthSession::HandleChallenge(const picojson::value& value) {
+  SessionData session_data;
+  session_data.FromJSON(value.get("sessionData"));
+  GVariant* vsess = session_data.ToVariant();
+  signon_auth_session_process_async(session_, vsess,
+      value.get("mechanism").to_str().c_str(), 0, &SSOAuthSession::ChallengeCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOAuthSession::HandleCancel(const picojson::value& value) {
+  SSOAsyncOp op(instance_, new picojson::value(value), this);
+  signon_auth_session_cancel(session_);
+  op.PostResult(jsid());
+}
+
+picojson::value SSOAuthSession::ToJSON() const {
+  picojson::value::object object;
+  object["method"] = picojson::value(method_);
+  object["sessionJSId"] = picojson::value(static_cast<double>(jsid_));
+  object["sessionState"] = picojson::value(static_cast<double>(session_state_));
+  return picojson::value(object);
+}
diff --git a/sso/sso_auth_session.h b/sso/sso_auth_session.h
new file mode 100644 (file)
index 0000000..cf791ba
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SSO_SSO_AUTH_SESSION_H_
+#define SSO_SSO_AUTH_SESSION_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libgsignon-glib/signon-auth-session.h>
+#include <libgsignon-glib/signon-utils.h>
+
+#include <memory>
+#include <string>
+
+#include "common/utils.h"
+#include "sso/sso_utils.h"
+
+namespace common {
+
+class Instance;
+
+}  // namespace common
+
+typedef enum {
+  SESSION_STATE_NOT_STARTED,
+  SESSION_STATE_RESOLVING_HOST,
+  SESSION_STATE_CONNECTING,
+  SESSION_STATE_SENDING_DATA,
+  SESSION_STATE_WAITING_REPLY,
+  SESSION_STATE_USER_PENDING,
+  SESSION_STATE_UI_REFRESHING,
+  SESSION_STATE_PROCESS_PENDING,
+  SESSION_STATE_STARTED,
+  SESSION_STATE_PROCESS_CANCELLING,
+  SESSION_STATE_PROCESS_DONE,
+  SESSION_STATE_CUSTOM
+} SessionState;
+
+class SessionData {
+ public:
+  SessionData();
+  virtual ~SessionData();
+
+  void FromJSON(const picojson::value& value);
+  picojson::value ToJSON() const;
+
+  GVariant* ToVariant() const;
+  void FromVariant(GVariant* vdata);
+
+ private:
+  GHashTable* data_;
+
+  bool IsSupportedType(GType type) const;
+  void ToJSONType(picojson::object& object, const gchar* key,
+      GValue* value) const;
+  void InsertStringData(const std::string& key, const picojson::value& obj);
+  void InsertData(const std::string& key, const picojson::value& obj);
+  bool InsertKnownData(const std::string& key, const picojson::value& obj);
+};
+
+class SSOAuthSession {
+ public:
+  SSOAuthSession(common::Instance* instance, SignonAuthSession* session,
+      const std::string& method, int jsid);
+  virtual ~SSOAuthSession();
+
+  int jsid() const { return jsid_; }
+  picojson::value ToJSON() const;
+
+  void HandleQueryAvailableMechanisms(const picojson::value& value);
+  void HandleChallenge(const picojson::value& value);
+  void HandleCancel(const picojson::value& value);
+
+ private:
+  static void QueryAvailableMechanismsCb(SignonAuthSession* self,
+      gchar** mechanisms, const GError* error, gpointer user_data);
+  static void ChallengeCb(GObject* source_object, GAsyncResult* res,
+      gpointer user_data);
+  static void StateChangeCb(SignonAuthSession* self, gint state, gchar* message,
+      gpointer user_data);
+
+  common::Instance* instance_;
+  SignonAuthSession* session_;
+  std::string method_;
+  SessionState session_state_;
+  int jsid_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSOAuthSession);
+};
+typedef std::shared_ptr<SSOAuthSession> SSOAuthSessionPtr;
+
+#endif  // SSO_SSO_AUTH_SESSION_H_
diff --git a/sso/sso_extension.cc b/sso/sso_extension.cc
new file mode 100644 (file)
index 0000000..4f3452e
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sso/sso_extension.h"
+
+#include <glib-object.h>
+
+#include "sso/sso_instance.h"
+
+common::Extension* CreateExtension() {
+#if !GLIB_CHECK_VERSION (2, 36, 0)
+  g_type_init();
+#endif
+  return new SSOExtension();
+}
+
+extern const char kSource_sso_api[];
+
+SSOExtension::SSOExtension() {
+  SetExtensionName("tizen.sso");
+  SetJavaScriptAPI(kSource_sso_api);
+}
+
+SSOExtension::~SSOExtension() {
+}
+
+common::Instance* SSOExtension::CreateInstance() {
+  return new SSOInstance();
+}
diff --git a/sso/sso_extension.h b/sso/sso_extension.h
new file mode 100644 (file)
index 0000000..feeb06f
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SSO_SSO_EXTENSION_H_
+#define SSO_SSO_EXTENSION_H_
+
+#include "common/extension.h"
+
+class SSOExtension: public common::Extension {
+ public:
+  SSOExtension();
+  virtual ~SSOExtension();
+
+ private:
+  // common::Extension implementation.
+  virtual common::Instance* CreateInstance();
+};
+
+#endif  // SSO_SSO_EXTENSION_H_
diff --git a/sso/sso_identity.cc b/sso/sso_identity.cc
new file mode 100644 (file)
index 0000000..285b215
--- /dev/null
@@ -0,0 +1,231 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sso/sso_identity.h"
+
+#include "sso/sso_async_op.h"
+#include "sso/sso_instance.h"
+#include "sso/sso_utils.h"
+
+IdentityFilterItem::IdentityFilterItem() {
+}
+
+IdentityFilterItem::~IdentityFilterItem() {
+}
+
+void IdentityFilterItem::FromJSON(const std::string& key,
+    const picojson::value& value) {
+  key_ = key;
+  if (value.contains("value_"))
+    value_ = value.get("value").to_str();
+}
+
+GHashTable* IdentityFilterItem::FromJSONValueArray(
+    const picojson::object& object) {
+  GHashTable* filters = NULL;
+  if (!object.empty())
+    filters = g_hash_table_new_full((GHashFunc) g_str_hash,
+        (GEqualFunc) g_str_equal, (GDestroyNotify) g_free,
+        (GDestroyNotify) g_free);
+  picojson::object::const_iterator it;
+  for (it = object.begin(); it != object.end(); ++it) {
+    IdentityFilterItem item;
+    item.FromJSON(it->first, picojson::value(it->second));
+    g_hash_table_insert(filters, g_strdup(item.key_.c_str()),
+        g_strdup(item.value_.c_str()));
+  }
+  return filters;
+}
+
+void SSOIdentity::PostResultCb(SignonIdentity* self, const GError* error,
+    gpointer user_data) {
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOIdentity* identity = reinterpret_cast<SSOIdentity*>(
+      async_op->user_data());
+  if (error) {
+    async_op->PostError(error->message, identity->jsid());
+    delete async_op;
+    return;
+  }
+  async_op->PostResult(identity->jsid());
+  delete async_op;
+}
+
+void SSOIdentity::StoreCb(SignonIdentity* self, guint32 id, const GError* error,
+    gpointer user_data) {
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOIdentity* identity = reinterpret_cast<SSOIdentity*>(
+      async_op->user_data());
+  if (error) {
+    async_op->PostError(error->message, identity->jsid());
+    delete async_op;
+    return;
+  }
+  identity->set_identity_id(id);
+  picojson::value::object resp;
+  resp["identityId"] = picojson::value(static_cast<double>(
+      identity->identity_id()));
+  async_op->PostResult(picojson::value(resp), identity->jsid());
+  delete async_op;
+}
+
+void SSOIdentity::VerifyUserCb(SignonIdentity* self, gboolean valid,
+    const GError* error, gpointer user_data) {
+  SSOAsyncOp* async_op = reinterpret_cast<SSOAsyncOp*>(user_data);
+  SSOIdentity* identity = reinterpret_cast<SSOIdentity*>(
+      async_op->user_data());
+  if (error) {
+    async_op->PostError(error->message, identity->jsid());
+    delete async_op;
+    return;
+  }
+  picojson::value::object resp;
+  resp["valid"] = picojson::value(static_cast<bool>(valid));
+  async_op->PostResult(picojson::value(resp), identity->jsid());
+  delete async_op;
+}
+
+void SSOIdentity::SignedoutSignalCb(gpointer self, gpointer user_data) {
+  SSOIdentity* identity = reinterpret_cast<SSOIdentity*>(user_data);
+  SSOAsyncOp op(identity->instance_, 0, identity);
+  picojson::value::object info;
+  info["info"] = picojson::value("signedout");
+  op.PostInfo(picojson::value(info), identity->jsid());
+}
+
+void SSOIdentity::RemovedSignalCb(gpointer self, gpointer user_data) {
+  SSOIdentity* identity = reinterpret_cast<SSOIdentity*>(user_data);
+  SSOAsyncOp op(identity->instance_, 0, identity);
+  picojson::value::object info;
+  info["info"] = picojson::value("removed");
+  op.PostInfo(picojson::value(info), identity->jsid());
+}
+
+SSOIdentity::SSOIdentity(common::Instance* instance, SignonIdentity* identity,
+    int identity_id, int jsid)
+    : instance_(instance), identity_(identity), identity_id_(identity_id),
+      jsid_(jsid) {
+  if (identity_) {
+    g_signal_connect(identity_, "signout",
+        G_CALLBACK(&SSOIdentity::SignedoutSignalCb), this);
+    g_signal_connect(identity_, "removed",
+        G_CALLBACK(&SSOIdentity::RemovedSignalCb), this);
+  }
+}
+
+SSOIdentity::~SSOIdentity() {
+  if (identity_) {
+    g_object_unref(identity_);
+    identity_ = NULL;
+  }
+}
+
+void SSOIdentity::HandleStartSession(const picojson::value& value) {
+  GError* error = NULL;
+  std::string method = value.get("method").to_str();
+  SignonAuthSession* session = signon_identity_create_session(identity_,
+      method.c_str(), &error);
+  SSOAsyncOp op(instance_, new picojson::value(value), this);
+  if (error) {
+    op.PostError(error->message, jsid());
+    g_clear_error(&error);
+    return;
+  }
+  SSOAuthSessionPtr sess_ptr = AddAuthSession(session, method,
+      static_cast<int>(value.get("sessionJSId").get<double>()));
+  op.PostResult(sess_ptr->ToJSON(), jsid());
+}
+
+void SSOIdentity::HandleDestroySession(const picojson::value& value) {
+  sessions_.erase(static_cast<int>(value.get("sessionJSId").get<double>()));
+}
+
+void SSOIdentity::HandleRequestCredentialsUpdate(const picojson::value& value) {
+  signon_identity_request_credentials_update(identity_,
+      reinterpret_cast<const gchar*>(value.get("message").to_str().c_str()),
+      &SSOIdentity::PostResultCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOIdentity::HandleStore(const picojson::value& value,
+    const std::string& appcontext) {
+  SSOIdentityInfo info(NULL);
+  info.FromJSON(value.get("info"), appcontext);
+  signon_identity_store_credentials_with_info(identity_,
+      reinterpret_cast<const SignonIdentityInfo*>(info.info()),
+      &SSOIdentity::StoreCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOIdentity::HandleAddReference(const picojson::value& value) {
+  signon_identity_add_reference(identity_,
+      reinterpret_cast<const gchar*>(value.get("reference").to_str().c_str()),
+      &SSOIdentity::PostResultCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOIdentity::HandleRemoveReference(const picojson::value& value) {
+  signon_identity_remove_reference(identity_,
+      reinterpret_cast<const gchar*>(value.get("reference").to_str().c_str()),
+      &SSOIdentity::PostResultCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOIdentity::HandleVerifyUser(const picojson::value& value) {
+  picojson::object obj;
+  obj["message"] = value.get("message");
+  GVariant* args = ArgsToVariant(obj);
+  signon_identity_verify_user(identity_, args, &SSOIdentity::VerifyUserCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOIdentity::HandleVerifyUserPrompt(const picojson::value& value) {
+  GVariant* args = ArgsToVariant(value.get<picojson::object>());
+  signon_identity_verify_user(identity_, args, &SSOIdentity::VerifyUserCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOIdentity::HandleRemove(const picojson::value& value) {
+  signon_identity_remove(identity_, &SSOIdentity::PostResultCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+void SSOIdentity::HandleSignOut(const picojson::value& value) {
+  signon_identity_signout(identity_, &SSOIdentity::PostResultCb,
+      new SSOAsyncOp(instance_, new picojson::value(value), this));
+}
+
+SSOAuthSessionPtr SSOIdentity::AddAuthSession(SignonAuthSession* session,
+    const std::string& method, int jsid) {
+  SSOAuthSessionPtr authsession_ptr;
+  std::map<int, SSOAuthSessionPtr>::const_iterator it = sessions_.find(jsid);
+  if (it != sessions_.end()) {
+    authsession_ptr = it->second;
+  } else {
+    authsession_ptr = std::make_shared<SSOAuthSession>(instance_, session,
+        method, jsid);
+    sessions_.insert(std::make_pair(jsid, authsession_ptr));
+  }
+  return authsession_ptr;
+}
+
+SSOAuthSessionPtr SSOIdentity::GetAuthSessionPtr(int jsid) const {
+  SSOAuthSessionPtr authsession_ptr;
+  std::map<int, SSOAuthSessionPtr>::const_iterator it = sessions_.find(jsid);
+  if (it != sessions_.end())
+    authsession_ptr = it->second;
+  return authsession_ptr;
+}
+
+GVariant* SSOIdentity::ArgsToVariant(const picojson::object& obj) {
+  GVariantBuilder builder;
+  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+  picojson::object::const_iterator it;
+  for (it = obj.begin(); it != obj.end(); ++it) {
+    std::string key = it->first;
+    picojson::value val = it->second;
+    g_variant_builder_add(&builder, "{sv}", key.c_str(), val.to_str().c_str());
+  }
+  return g_variant_builder_end(&builder);
+}
diff --git a/sso/sso_identity.h b/sso/sso_identity.h
new file mode 100644 (file)
index 0000000..7a5b933
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SSO_SSO_IDENTITY_H_
+#define SSO_SSO_IDENTITY_H_
+
+#include <libgsignon-glib/signon-identity.h>
+#include <libgsignon-glib/signon-identity-info.h>
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "common/picojson.h"
+#include "common/utils.h"
+#include "sso/sso_auth_session.h"
+#include "sso/sso_identity_info.h"
+
+namespace common {
+
+class Instance;
+
+}  // namespace common
+
+typedef enum {
+  USER_PROMPT_POLICY_DEFAULT,
+  USER_PROMPT_POLICY_REQUEST_PASSWORD,
+  USER_PROMPT_POLICY_NO_USER_INTERACTION,
+  USER_PROMPT_POLICY_VALIDATION
+} UserPromptPolicy;
+
+class IdentityFilterItem {
+ public:
+  IdentityFilterItem();
+  ~IdentityFilterItem();
+
+  static GHashTable* FromJSONValueArray(const picojson::object& object);
+
+ private:
+  std::string key_;
+  std::string value_;
+
+  void FromJSON(const std::string& key, const picojson::value& value);
+};
+
+class SSOIdentity {
+ public:
+  SSOIdentity(common::Instance* instance, SignonIdentity* identity,
+      int identity_id, int jsid);
+  virtual ~SSOIdentity();
+
+  int jsid() const { return jsid_; }
+  int identity_id() const { return identity_id_; }
+  void set_identity_id(int id) { identity_id_ = id; }
+
+  SSOAuthSessionPtr GetAuthSessionPtr(int jsid) const;
+
+  void HandleStartSession(const picojson::value& value);
+  void HandleDestroySession(const picojson::value& value);
+  void HandleRequestCredentialsUpdate(const picojson::value& value);
+  void HandleStore(const picojson::value& value, const std::string& appcontext);
+  void HandleAddReference(const picojson::value& value);
+  void HandleRemoveReference(const picojson::value& value);
+  void HandleVerifyUser(const picojson::value& value);
+  void HandleVerifyUserPrompt(const picojson::value& value);
+  void HandleRemove(const picojson::value& value);
+  void HandleSignOut(const picojson::value& value);
+
+ private:
+  static void PostResultCb(SignonIdentity* self, const GError* error,
+      gpointer user_data);
+  static void StoreCb(SignonIdentity* self, guint32 id, const GError* error,
+      gpointer user_data);
+  static void VerifyUserCb(SignonIdentity* self, gboolean valid,
+      const GError* error, gpointer user_data);
+  static void SignedoutSignalCb(gpointer self, gpointer user_data);
+  static void RemovedSignalCb(gpointer self, gpointer user_data);
+  GVariant* ArgsToVariant(const picojson::object& obj);
+  SSOAuthSessionPtr AddAuthSession(SignonAuthSession* session,
+      const std::string& method, int jsid);
+
+  common::Instance* instance_;
+  SignonIdentity* identity_;
+  std::map<int, SSOAuthSessionPtr> sessions_;
+  int jsid_;
+  int identity_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSOIdentity);
+};
+typedef std::shared_ptr<SSOIdentity> SSOIdentityPtr;
+
+#endif  // SSO_SSO_IDENTITY_H_
diff --git a/sso/sso_identity_info.cc b/sso/sso_identity_info.cc
new file mode 100644 (file)
index 0000000..6fa0582
--- /dev/null
@@ -0,0 +1,260 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sso/sso_identity_info.h"
+
+#include <libgsignon-glib/signon-security-context.h>
+
+SecurityContext::SecurityContext() {
+}
+
+SecurityContext::~SecurityContext() {
+}
+
+void SecurityContext::FromJSON(const picojson::value& value) {
+  if (value.contains("sysContext"))
+    sys_context_ = value.get("sysContext").to_str();
+  if (value.contains("appContext"))
+    app_context_ = value.get("appContext").to_str();
+}
+
+picojson::value SecurityContext::ToJSON() const {
+  picojson::value::object object;
+  object["sys_context"] = picojson::value(sys_context_);
+  object["app_context"] = picojson::value(app_context_);
+  return picojson::value(object);
+}
+
+bool SecurityContext::ContainsData() const {
+  return (!sys_context_.empty() || !app_context_.empty());
+}
+
+ACLEntry::ACLEntry() {
+}
+
+ACLEntry::~ACLEntry() {
+}
+
+void ACLEntry::FromJSON(const picojson::value& value) {
+  if (value.contains("securityContext"))
+    security_context_.FromJSON(value.get("securityContext"));
+  if (value.contains("method"))
+    method_ = value.get("method").to_str();
+  if (value.contains("mechanisms"))
+    mechanisms_ = SSOUtils::FromJSONArrayToStringVector(
+        value.get("mechanisms").get<picojson::array>());
+}
+
+picojson::value ACLEntry::ToJSON() const {
+  picojson::value::object object;
+  if (security_context_.ContainsData())
+    object["security_context"] = security_context_.ToJSON();
+  if (!method_.empty())
+    object["method"] = picojson::value(method_);
+  if (!mechanisms_.empty())
+    object["mechanisms"] = picojson::value(
+        SSOUtils::FromStringVectorToJSONArray(
+            (const std::vector<std::string>&) mechanisms_));
+  return picojson::value(object);
+}
+
+std::vector<ACLEntry> ACLEntry::FromJSONValueArray(
+    const picojson::array& array) {
+  std::vector<ACLEntry> acl;
+  picojson::array::const_iterator it;
+  for (it = array.begin(); it != array.end(); ++it) {
+    ACLEntry entry;
+    entry.FromJSON(*it);
+    acl.push_back(entry);
+  }
+  return acl;
+}
+
+picojson::value ACLEntry::ToJSONValueArray(
+    const std::vector<ACLEntry>& entries) {
+  picojson::array array;
+  std::vector<ACLEntry>::const_iterator it;
+  for (it = entries.begin(); it != entries.end(); ++it) {
+    ACLEntry entry = *it;
+    if (entry.ContainsData())
+      array.push_back(entry.ToJSON());
+  }
+  return picojson::value(array);
+}
+
+bool ACLEntry::ContainsData() const {
+  return (security_context_.ContainsData() ||
+      !method_.empty() ||
+      !mechanisms_.empty());
+}
+
+void SSOIdentityInfo::AddMethodMechanisms(gpointer method, gpointer mechanisms,
+    gpointer user_data) {
+  ACLEntry* entry = reinterpret_cast<ACLEntry*>(user_data);
+  entry->set_method(std::string(reinterpret_cast<const gchar*>(method)));
+  entry->set_mechanisms(SSOUtils::FromStringArrayToStringVector(
+      reinterpret_cast<const gchar* const*>(mechanisms)));
+}
+
+std::vector<ACLEntry> SSOIdentityInfo::GetACL(SignonIdentityInfo* info) const {
+  std::vector<ACLEntry> acl;
+  SignonSecurityContextList* info_acl =
+      signon_identity_info_get_access_control_list(info);
+  if (!info_acl)
+    return acl;
+
+  for (info_acl = g_list_first(info_acl);
+       info_acl != NULL;
+       info_acl = g_list_next(info_acl)) {
+    const SignonSecurityContext* context =
+        reinterpret_cast<const SignonSecurityContext*>(info_acl->data);
+    const gchar* sysctx = signon_security_context_get_system_context(context);
+    SecurityContext ctx;
+    if (sysctx)
+      ctx.set_sys_context(sysctx);
+
+    const gchar* appctx = signon_security_context_get_application_context(
+        context);
+    if (appctx)
+      ctx.set_app_context(appctx);
+    ACLEntry entry;
+    entry.set_security_context(ctx);
+
+    GHashTable* methods = signon_identity_info_get_methods(info);
+    if (methods)
+      g_hash_table_foreach(methods, &SSOIdentityInfo::AddMethodMechanisms,
+          &entry);
+    if (sysctx || appctx || methods)
+      acl.push_back(entry);
+  }
+  return acl;
+}
+
+SecurityContext SSOIdentityInfo::GetOwner(SignonIdentityInfo* info) const {
+  const SignonSecurityContext* context = signon_identity_info_get_owner(info);
+  SecurityContext ctx;
+  if (context) {
+    ctx.set_app_context(context->app_ctx);
+    ctx.set_sys_context(context->sys_ctx);
+  }
+  return ctx;
+}
+
+SSOIdentityInfo::SSOIdentityInfo(SignonIdentityInfo* info)
+    : info_(0) {
+  if (info)
+    info_ = signon_identity_info_copy(info);
+}
+
+SSOIdentityInfo::~SSOIdentityInfo() {
+  if (info_) {
+    signon_identity_info_free(info_);
+    info_ = NULL;
+  }
+}
+
+void SSOIdentityInfo::FromJSON(const picojson::value& value,
+    const std::string& appcontext) {
+  if (info_)
+    signon_identity_info_free(info_);
+  info_ = signon_identity_info_new();
+  if (value.contains("type"))
+    signon_identity_info_set_identity_type(info_,
+        static_cast<SignonIdentityType>(value.get("type").get<double>()));
+
+  if (value.contains("username"))
+    signon_identity_info_set_username(info_,
+        value.get("username").to_str().c_str());
+
+  if (value.contains("secret"))
+    signon_identity_info_set_secret(info_, value.get("secret").to_str().c_str(),
+        value.get("storeSecret").get<bool>());
+
+  if (value.contains("caption"))
+    signon_identity_info_set_caption(info_,
+        value.get("caption").to_str().c_str());
+
+  if (value.contains("realms")) {
+    gchar** strv = SSOUtils::FromJSONArrayToStringArray(
+        value.get("realms").get<picojson::array>());
+    if (strv) {
+      signon_identity_info_set_realms(info_,
+          reinterpret_cast<const gchar* const*>(strv));
+      g_strfreev(strv);
+    }
+  }
+
+  if (value.contains("owner")) {
+    SecurityContext ctx;
+    ctx.FromJSON(value.get("owner"));
+    if (ctx.app_context().empty())
+      ctx.set_app_context(appcontext);
+    if (ctx.ContainsData()) {
+      signon_identity_info_set_owner_from_values(info_,
+          ctx.sys_context().c_str(), ctx.app_context().c_str());
+    }
+  }
+
+  if (value.contains("accessControlList")) {
+    std::vector<ACLEntry> acl = ACLEntry::FromJSONValueArray(
+        value.get("accessControlList").get<picojson::array>());
+    std::vector<ACLEntry>::const_iterator it;
+    for (it = acl.begin(); it != acl.end(); ++it) {
+      ACLEntry entry = *it;
+      if (!entry.method().empty() && !entry.mechanisms().empty()) {
+        gchar** mechs = SSOUtils::FromStringVectorToStringArray(
+            entry.mechanisms());
+        if (mechs) {
+          signon_identity_info_set_method(info_, entry.method().c_str(),
+              reinterpret_cast<const gchar* const*>(mechs));
+          g_strfreev(mechs);
+        }
+      }
+      if (entry.security_context().ContainsData()) {
+        SignonSecurityContext* sc = signon_security_context_new_from_values(
+            entry.security_context().sys_context().c_str(),
+            entry.security_context().app_context().c_str());
+        signon_identity_info_access_control_list_append(info_, sc);
+      }
+    }
+  }
+}
+
+picojson::value SSOIdentityInfo::ToJSON() const {
+  picojson::value::object object;
+  if (!info_)
+    return picojson::value(object);
+
+  object["id"] = picojson::value(
+      static_cast<double>(signon_identity_info_get_id(info_)));
+
+  SignonIdentityType type = signon_identity_info_get_identity_type(info_);
+  object["type"] = picojson::value(static_cast<double>(type));
+
+  const gchar* str = signon_identity_info_get_username(info_);
+  if (str)
+    object["username"] = picojson::value(std::string(str));
+
+  object["store_secret"] = picojson::value(
+      static_cast<bool>(signon_identity_info_get_storing_secret(info_)));
+
+  str = signon_identity_info_get_caption(info_);
+  if (str)
+    object["caption"] = picojson::value(std::string(str));
+
+  const gchar* const* strv = signon_identity_info_get_realms(info_);
+  if (strv)
+    object["realms"] = picojson::value(
+        SSOUtils::FromStringArrayToJSONArray(strv));
+
+  SecurityContext owner = GetOwner(info_);
+  if (!owner.app_context().empty() || !owner.sys_context().empty())
+    object["owner"] = owner.ToJSON();
+
+  std::vector<ACLEntry> acl = GetACL(info_);
+  if (!acl.empty())
+    object["access_control_list"] = ACLEntry::ToJSONValueArray(acl);
+
+  return picojson::value(object);
+}
diff --git a/sso/sso_identity_info.h b/sso/sso_identity_info.h
new file mode 100644 (file)
index 0000000..e29a1dd
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SSO_SSO_IDENTITY_INFO_H_
+#define SSO_SSO_IDENTITY_INFO_H_
+
+#include <libgsignon-glib/signon-identity-info.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "common/picojson.h"
+#include "common/utils.h"
+#include "sso/sso_utils.h"
+
+class SecurityContext {
+ public:
+  SecurityContext();
+  ~SecurityContext();
+
+  const std::string& sys_context() const { return sys_context_; }
+  void set_sys_context(const std::string& sc) { sys_context_ = sc; }
+  const std::string& app_context() const { return app_context_; }
+  void set_app_context(const std::string& ac) { app_context_ = ac; }
+
+  void FromJSON(const picojson::value& value);
+  picojson::value ToJSON() const;
+
+  bool ContainsData() const;
+
+ private:
+  std::string sys_context_;
+  std::string app_context_;
+};
+
+class ACLEntry {
+ public:
+  ACLEntry();
+  ~ACLEntry();
+
+  const SecurityContext& security_context() const { return security_context_; }
+  void set_security_context(const SecurityContext& ctx) {
+    security_context_ = ctx;
+  }
+  const std::string& method() const { return method_; }
+  void set_method(const std::string& method) { method_ = method; }
+  const std::vector<std::string>& mechanisms() const { return mechanisms_; }
+  void set_mechanisms(const std::vector<std::string>& mechs) {
+    mechanisms_ = mechs;
+  }
+
+  static std::vector<ACLEntry> FromJSONValueArray(const picojson::array& array);
+  static picojson::value ToJSONValueArray(const std::vector<ACLEntry>& entries);
+  bool ContainsData() const;
+
+ private:
+  SecurityContext security_context_;
+  std::string method_;
+  std::vector<std::string> mechanisms_;
+
+  void FromJSON(const picojson::value& value);
+  picojson::value ToJSON() const;
+};
+
+class SSOIdentityInfo {
+ public:
+  explicit SSOIdentityInfo(SignonIdentityInfo* info);
+  virtual ~SSOIdentityInfo();
+
+  void FromJSON(const picojson::value& value, const std::string& appcontext);
+  picojson::value ToJSON() const;
+
+  SignonIdentityInfo* info() const { return info_; }
+
+ private:
+  SecurityContext GetOwner(SignonIdentityInfo* info) const;
+  std::vector<ACLEntry> GetACL(SignonIdentityInfo* info) const;
+  static void AddMethodMechanisms(gpointer method, gpointer mechanisms,
+      gpointer user_data);
+
+  SignonIdentityInfo* info_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSOIdentityInfo);
+};
+typedef std::shared_ptr<SSOIdentityInfo> SSOIdentityInfoPtr;
+
+#endif  // SSO_SSO_IDENTITY_INFO_H_
diff --git a/sso/sso_instance.cc b/sso/sso_instance.cc
new file mode 100644 (file)
index 0000000..63d100c
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sso/sso_instance.h"
+
+#include <sstream>
+#include <string>
+
+#include "common/picojson.h"
+#include "sso/sso_async_op.h"
+#include "sso/sso_auth_service.h"
+
+SSOInstance::SSOInstance() {
+  std::string id_str = common::Extension::GetRuntimeVariable("app_id", 64);
+  std::istringstream buf(id_str);
+  picojson::value id_val;
+  picojson::parse(id_val, buf);
+  sso_auth_service_ = new SSOAuthService(this, id_val.get<std::string>());
+}
+
+SSOInstance::~SSOInstance() {
+  delete sso_auth_service_;
+}
+
+SSOAuthService* SSOInstance::GetService(const picojson::value& v) const {
+  SSOAuthService* service = 0;
+  int jsid = static_cast<int>(v.get("serviceJSId").get<double>());
+  if (sso_auth_service_->jsid() == -1) {
+    sso_auth_service_->set_jsid(jsid);
+    service = sso_auth_service_;
+  } else if (jsid == sso_auth_service_->jsid()) {
+    service = sso_auth_service_;
+  }
+  return service;
+}
+
+SSOIdentityPtr SSOInstance::GetIdentity(const picojson::value& v) const {
+  int jsid = static_cast<int>(v.get("identityJSId").get<double>());
+  return sso_auth_service_->GetIdentityPtr(jsid);
+}
+
+SSOAuthSessionPtr SSOInstance::GetAuthSession(const picojson::value& v) const {
+  int jsid = static_cast<int>(v.get("sessionJSId").get<double>());
+  return sso_auth_service_->GetAuthSessionPtr(jsid);
+}
+
+void SSOInstance::PostError(const picojson::value& v, const std::string& msg) {
+  SSOAsyncOp op(this, new picojson::value(v), 0);
+  op.PostError(msg.c_str(), -1);
+}
+
+void SSOInstance::HandleAuthServiceMessage(const std::string& cmd,
+    const picojson::value& v) {
+  SSOAuthService* service = GetService(v);
+  if (!service) {
+    PostError(v, "Invalid Service Object");
+    return;
+  }
+
+  if (cmd == "queryMethods") {
+    service->HandleQueryMethods(v);
+  } else if (cmd == "queryMechanisms") {
+    service->HandleQueryMechanisms(v);
+  } else if (cmd == "queryIdentities") {
+    service->HandleQueryIdentities(v);
+  } else if (cmd == "getIdentity") {
+    service->HandleGetIdentity(v);
+  } else if (cmd == "destroyIdentity") {
+    service->HandleDestroyIdentity(v);
+  } else if (cmd == "clear") {
+    service->HandleClear(v);
+  } else {
+    std::cerr << "Received unknown message: " << cmd << "\n";
+  }
+}
+
+void SSOInstance::HandleIdentityMessage(const std::string& cmd,
+    const picojson::value& v) {
+  SSOIdentityPtr identity = GetIdentity(v);
+  if (!identity) {
+    PostError(v, "Invalid Identity Object");
+    return;
+  }
+
+  if (cmd == "startSession") {
+    identity->HandleStartSession(v);
+  } else if (cmd == "destroySession") {
+    identity->HandleDestroySession(v);
+  } else if (cmd == "requestCredentialsUpdate") {
+    identity->HandleRequestCredentialsUpdate(v);
+  } else if (cmd == "store") {
+    identity->HandleStore(v, sso_auth_service_->appcontext());
+  } else if (cmd == "addReference") {
+    identity->HandleAddReference(v);
+  } else if (cmd == "removeReference") {
+    identity->HandleRemoveReference(v);
+  } else if (cmd == "verifyUser") {
+    identity->HandleVerifyUser(v);
+  } else if (cmd == "verifyUserPrompt") {
+    identity->HandleVerifyUserPrompt(v);
+  } else if (cmd == "remove") {
+    identity->HandleRemove(v);
+  } else if (cmd == "signout") {
+    identity->HandleSignOut(v);
+  } else {
+    std::cerr << "Received unknown message: " << cmd << "\n";
+  }
+}
+
+void SSOInstance::HandleAuthSessionMessage(const std::string& cmd,
+    const picojson::value& v) {
+  SSOAuthSessionPtr session = GetAuthSession(v);
+  if (!session) {
+    PostError(v, "Invalid AuthSession Object");
+    return;
+  }
+
+  if (cmd == "queryAvailableMechanisms") {
+    session->HandleQueryAvailableMechanisms(v);
+  } else if (cmd == "challenge") {
+    session->HandleChallenge(v);
+  } else if (cmd == "cancel") {
+    session->HandleCancel(v);
+  } else {
+    std::cerr << "Received unknown message: " << cmd << "\n";
+  }
+}
+
+void SSOInstance::HandleMessage(const char* message) {
+  picojson::value v;
+
+  std::string err;
+  picojson::parse(v, message, message + strlen(message), &err);
+  if (!err.empty()) {
+    return;
+  }
+  std::string cmd = v.get("asyncOpCmd").to_str();
+  if (cmd == "queryMethods" ||
+      cmd == "queryMechanisms" ||
+      cmd == "queryIdentities" ||
+      cmd == "getIdentity" ||
+      cmd == "destroyIdentity" ||
+      cmd == "clear") {
+    HandleAuthServiceMessage(cmd, v);
+  } else if (cmd == "startSession" ||
+      cmd == "requestCredentialsUpdate" ||
+      cmd == "store" ||
+      cmd == "addReference" ||
+      cmd == "removeReference" ||
+      cmd == "verifyUser" ||
+      cmd == "verifyUserPrompt" ||
+      cmd == "remove" ||
+      cmd == "signout") {
+    HandleIdentityMessage(cmd, v);
+  } else if (cmd == "queryAvailableMechanisms" ||
+      cmd == "challenge" ||
+      cmd == "cancel") {
+    HandleAuthSessionMessage(cmd, v);
+  } else {
+    std::cerr << "Received unknown message: " << cmd << "\n";
+  }
+}
+
+void SSOInstance::HandleSyncMessage(const char* message) {
+  picojson::value::object obj;
+  picojson::value v;
+  std::string err;
+  picojson::parse(v, message, message + strlen(message), &err);
+  if (!err.empty()) {
+    obj["synOpErrorMsg"] = picojson::value("Unable to parse message");
+    SendSyncReply(picojson::value(obj).serialize().c_str());
+    return;
+  }
+
+  std::string cmd = v.get("syncOpCmd").to_str();
+  SSOAuthService* service = 0;
+  if (cmd == "createIdentity") {
+    service = GetService(v);
+    if (service)
+      service->HandleCreateIdentity(v);
+    else
+      obj["synOpErrorMsg"] = picojson::value("Invalid Service Object");
+  } else {
+    obj["synOpErrorMsg"] = picojson::value("Unknown sync command");
+  }
+  SendSyncReply(picojson::value(obj).serialize().c_str());
+}
diff --git a/sso/sso_instance.h b/sso/sso_instance.h
new file mode 100644 (file)
index 0000000..d46b086
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SSO_SSO_INSTANCE_H_
+#define SSO_SSO_INSTANCE_H_
+
+#include <string>
+#include <thread>  // NOLINT
+
+#include "common/extension.h"
+#include "sso/sso_auth_session.h"
+#include "sso/sso_identity.h"
+
+class SSOAuthService;
+
+class SSOInstance: public common::Instance {
+ public:
+  SSOInstance();
+  virtual ~SSOInstance();
+
+ private:
+  // common::Instance implementation.
+  virtual void HandleMessage(const char* msg);
+  virtual void HandleSyncMessage(const char* msg);
+
+  SSOAuthService* GetService(const picojson::value& v) const;
+  SSOIdentityPtr GetIdentity(const picojson::value& v) const;
+  SSOAuthSessionPtr GetAuthSession(const picojson::value& v) const;
+
+  void HandleAuthServiceMessage(const std::string& cmd,
+      const picojson::value& v);
+  void HandleIdentityMessage(const std::string& cmd, const picojson::value& v);
+  void HandleAuthSessionMessage(const std::string& cmd,
+      const picojson::value& v);
+  void PostError(const picojson::value& v, const std::string& msg);
+
+  SSOAuthService* sso_auth_service_;
+};
+
+#endif  // SSO_SSO_INSTANCE_H_
diff --git a/sso/sso_utils.cc b/sso/sso_utils.cc
new file mode 100644 (file)
index 0000000..10c9372
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sso/sso_utils.h"
+
+#include <glib.h>
+
+SSOUtils::SSOUtils() {
+}
+
+SSOUtils::~SSOUtils() {
+}
+
+picojson::value SSOUtils::FromStringToJSONValue(const char* string) {
+  return string ? picojson::value(string) : picojson::value();
+}
+
+picojson::array SSOUtils::FromStringArrayToJSONArray(
+    const char* const* strings) {
+  picojson::array array;
+  while (*strings) {
+    array.push_back(picojson::value(*strings++));
+  }
+  return array;
+}
+
+char** SSOUtils::FromJSONArrayToStringArray(const picojson::array& array) {
+  char** res = reinterpret_cast<char**>(g_malloc0(
+      sizeof(char*) * (array.size() + 1)));
+  std::vector<picojson::value>::const_iterator it;
+  gint i = 0;
+  for (it = array.begin(); it != array.end(); ++it) {
+    picojson::value val = *it;
+    res[i++] = g_strdup(val.to_str().c_str());
+  }
+  return res;
+}
+
+picojson::array SSOUtils::FromStringVectorToJSONArray(
+    const std::vector<std::string>& vector) {
+  picojson::array array;
+  std::vector<std::string>::const_iterator it;
+  for (it = vector.begin(); it != vector.end(); ++it) {
+    array.push_back(picojson::value(*it));
+  }
+  return array;
+}
+
+std::vector<std::string> SSOUtils::FromJSONArrayToStringVector(
+    const picojson::array& array) {
+  std::vector<std::string> res;
+  picojson::array::const_iterator it;
+  for (it = array.begin(); it != array.end(); ++it) {
+    picojson::value val = *it;
+    res.push_back(val.to_str());
+  }
+  return res;
+}
+
+std::vector<std::string> SSOUtils::FromStringArrayToStringVector(
+    const char* const* strings) {
+  std::vector<std::string> vec;
+  if (strings) {
+    while (*strings)
+      vec.push_back(*strings++);
+  }
+  return vec;
+}
+
+char** SSOUtils::FromStringVectorToStringArray(
+    const std::vector<std::string>& vector) {
+  char** res = reinterpret_cast<char**>(g_malloc0(
+      sizeof(char*) * (vector.size() + 1)));
+  gint i = 0;
+  std::vector<std::string>::const_iterator it;
+  for (it = vector.begin(); it != vector.end(); ++it) {
+    res[i++] = g_strdup((*it).c_str());
+  }
+  return res;
+}
diff --git a/sso/sso_utils.h b/sso/sso_utils.h
new file mode 100644 (file)
index 0000000..cd89b88
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SSO_SSO_UTILS_H_
+#define SSO_SSO_UTILS_H_
+
+#include <string>
+#include <vector>
+
+#include "common/picojson.h"
+
+class SSOUtils {
+ public:
+  SSOUtils();
+  ~SSOUtils();
+
+  static picojson::value FromStringToJSONValue(const char* string);
+  static picojson::array FromStringArrayToJSONArray(
+      const char* const* strings);
+  static char** FromJSONArrayToStringArray(const picojson::array& array);
+  static picojson::array FromStringVectorToJSONArray(
+      const std::vector<std::string>& vector);
+  static std::vector<std::string> FromJSONArrayToStringVector(
+      const picojson::array& array);
+  static std::vector<std::string> FromStringArrayToStringVector(
+      const char* const* strings);
+  static char** FromStringVectorToStringArray(
+      const std::vector<std::string>& vector);
+};
+
+#endif  // SSO_SSO_UTILS_H_
index f2e8abb..a86957c 100644 (file)
@@ -42,6 +42,7 @@
           'dependencies': [
             'audiosystem/audiosystem.gyp:*',
             'vehicle/vehicle.gyp:*',
+            'sso/sso.gyp:*',
           ],
         }],
       ],