Permalink
Browse files

Updated method for storing consumer keys/tokens

  • Loading branch information...
1 parent 670cfc8 commit fcfb697eb23b3c7fb287571677b481abef4af820 @jimklo jimklo committed May 30, 2012
View
4 .gitignore
@@ -20,3 +20,7 @@ LR/*.backup
/data-pumps/oai-pmh-data-pump-config.json
/utils/testconfig.ini
+
+env
+couchdb/apps/kanso/oauth-key-management/packages
+couchdb/apps/kanso/restrict-writers/packages
View
1 LR/development.ini.orig
@@ -73,6 +73,7 @@ couchdb.threshold.distributes = 1000
couchdb.threshold.viewupdate = 100
couchdb.threshold.compaction = 10000
couchdb.stale.flag = update_after
+lr.oauth.signup = https://localhost:8443/apps/oauth-key-management
lr.distribute.url = http://localhost/distribute
lr.obtain.docid = access:Basic Obtain service
lr.harvest.docid = access:Basic Harvest service
View
1 LR/lr/config/routing.py
@@ -43,6 +43,7 @@ def mapResource(config_key, member_name, collection_name):
map.resource('filter', 'filters', controller='contrib/filters',
path_prefix='/contrib', name_prefix='contrib_')
map.resource("register","register")
+ map.resource("oauth","oauth")
mapResource('lr.status.docid', 'status','status')
mapResource('lr.distribute.docid','distribute','distribute')
if not LRNode.nodeDescription.gateway_node:
View
64 LR/lr/controllers/oauth.py
@@ -0,0 +1,64 @@
+import logging, browserid, json
+
+from pylons import config, request, response, session, tmpl_context as c, url
+from pylons.controllers.util import abort, redirect
+
+from lr.lib.base import BaseController, render
+
+log = logging.getLogger(__name__)
+
+appConfig = config['app_conf']
+
+class OauthController(BaseController):
+
+
+
+ def index(self):
+ response.headers['Content-Type'] = 'text/html;charset=utf-8'
+ # Return a rendered template
+ response.status_int = 301
+ response.headers['Location'] = appConfig['lr.oauth.signup']
+ return "Moved: %s" % appConfig['lr.oauth.signup']
+ # return render('/oauth.html')
+ # or, return a string
+ # return 'Hello World'
+ # response.headers['Pragma'] = 'no-cache'
+ # response.headers['Cache-Control'] = 'no-store,no-cache,must-revalidate,max-age=0'
+ # return abort(301, detail=appConfig['lr.oauth.signup'])
+
+ # return "Moved permanently: %s" % appConfig['lr.oauth.signup']
+
+ def verify(self):
+
+ pass
+
+ def login(self):
+ data = None
+ if request.method == 'POST' and "assertion" in request.POST:
+ data = browserid.verify(request.POST["assertion"], request.host_url)
+ log.debug(json.dumps(data))
+
+ if data['status'] == 'okay':
+ session['contact'] = data['email']
+ session.save()
+
+ return json.dumps(data)
+
+ def logout(self):
+ session.clear()
+ session.save()
+ return json.dumps({"status": "okay"})
+
+
+ def manage(self):
+ for i in request.POST.keys():
+ log.debug("{0} : {1}".format(i, request.POST[i]))
+
+ if 'contact' in session:
+ log.debug(session['contact'])
+
+ return
+
+
+
+
View
2 LR/lr/model/base_model.py
@@ -48,7 +48,7 @@ class BaseModel(object):
_ID = '_id'
_REV = '_rev'
_SPEC_DATA = '_specData'
-
+
_defaultDB = createDB(defaultDBName, server)
_modelParsers = getModelPasers(modelSpec)
View
7 LR/lr/tests/functional/test_oauth.py
@@ -0,0 +1,7 @@
+from lr.tests import *
+
+class TestOauthController(TestController):
+
+ def test_index(self):
+ response = self.app.get(url(controller='oauth', action='index'))
+ # Test response...
View
44 couchdb/apps/kanso/oauth-key-management/css/style.css
@@ -0,0 +1,44 @@
+
+div.oauth {
+ display: none;
+ width: 100%;
+ clear: both;
+}
+
+div.oauth label, div.oauth input {
+ display: block;
+ width: 100%;
+}
+
+div.head , div.credentials {
+ width: 100%;
+ clear: both;
+}
+
+#browserid {
+ width: auto;
+}
+
+div.login {
+
+}
+
+.head h2 {
+ float: left;
+ width: 60%;
+}
+
+
+.picture {
+ float: left;
+}
+
+img {
+ border: none;
+}
+
+.logo {
+ float: right;
+}
+
+.clear: both;
View
BIN couchdb/apps/kanso/oauth-key-management/images/learning-registry-logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
69 couchdb/apps/kanso/oauth-key-management/index.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script src="/_browserid/include.js" type="text/javascript"></script>
+
+ <!-- Optional styles -->
+ <link rel="stylesheet" type="text/css" href="/_browserid/style.css">
+ <link rel="stylesheet" type="text/css" href="css/style.css">
+ </head>
+
+ <body>
+ <div class="head">
+ <h2>OAuth Management for Sign on Publish</h2>
+ <img class="logo" src="images/learning-registry-logo.png">
+ </div>
+
+ <div class="credentials">
+ <div id="browserid">
+ <div class="picture"></div>
+ <div class="login">
+ <img src="/_browserid/sign_in_green.png">
+ </div>
+ </div>
+ </div>
+ <div class="msg"></div>
+ <div class="oauth">
+
+ <fieldset>
+ <legend>Signing Information</legend>
+ <p>The following will be appended to the resource data document's identity.signer field along with your email address so that your submissions may be identified.</p>
+ <label for="full_name">Full Name</label>
+ <input type="text" id="full_name">
+
+ <button id="info_update">Save</button>
+ </fieldset>
+ <fieldset>
+ <legend>2-Legged OAuth Config</legend>
+ <p>Use the following when connecting your application to LR to sign on your behalf. If the OAuth signature is present when you publish, the documents you publish will be signed by the node.</p>
+ <label for="consumer_key">oauth_consumer_key</label>
+ <input type="text" disabled="disabled" id="consumer_key" value="node_sign_key">
+
+ <label for="consumer_secret">oauth_consumer_secret</label>
+ <input type="text" disabled="disabled" id="consumer_secret">
+
+
+ <label for="token">oauth_token</label>
+ <input type="text" disabled="disabled" id="token" value="node_sign_token">
+
+ <label for="token_secret">oauth_token_secret</label>
+ <input type="text" disabled="disabled" id="token_secret">
+
+ <button id="regenerate">Revoke and Regenerate</button>
+ </fieldset>
+
+ </div>
+ </body>
+
+ <!-- Recommended convenience API -->
+ <script src="/_utils/script/jquery.js" type="text/javascript"></script>
+ <script src="/_utils/script/oauth.js" type="text/javascript"></script>
+ <script src="/_utils/script/sha1.js" type="text/javascript"></script>
+ <script src="/_browserid/main.js" type="text/javascript"></script>
+ <script src="modules.js" type="text/javascript"></script>
+ <script type="text/javascript">
+ var manage_tokens = require("lib/manage-tokens");
+
+ manage_tokens.registerCallbacks();
+ </script>
+</html>
View
15 couchdb/apps/kanso/oauth-key-management/kanso.json
@@ -0,0 +1,15 @@
+{
+ "name": "oauth-key-management",
+ "version": "0.0.1",
+ "description": "OAuth Key Management",
+ "attachments": ["index.html","css","images"],
+ "modules":["lib"],
+ "load": "lib/app",
+ "dependencies": {
+ "attachments": null,
+ "modules": null,
+ "users": null,
+ "underscore": null,
+ "properties": null
+ }
+}
View
0 couchdb/apps/kanso/oauth-key-management/lib/app.js
No changes.
View
147 couchdb/apps/kanso/oauth-key-management/lib/manage-tokens.js
@@ -0,0 +1,147 @@
+
+var session = require("session"),
+ users = require("users"),
+ _ = require("underscore")._;
+
+function getOAuth(email, doc, regenerate) {
+ if (regenerate || !(doc.oauth
+ && doc.oauth.consumer_keys
+ && doc.oauth.consumer_keys[email]
+ && doc.oauth.tokens
+ && doc.oauth.tokens.node_sign_token)) {
+
+ doc.oauth = doc.oauth || {};
+ doc.oauth.consumer_keys = doc.oauth.consumer_keys || {};
+ doc.oauth.tokens = doc.oauth.tokens || {};
+
+ doc.oauth.consumer_keys[email] = exports.generateSecret(32);
+ doc.oauth.tokens.node_sign_token = exports.generateSecret(32);
+
+ if (!doc.roles || _.indexOf(doc.roles, "node_sign") == -1) {
+ doc.roles = doc.roles || [];
+ // doc.roles.push("node_sign");
+ }
+
+ users.update(email, null, doc, function(err) {
+ if (err) {
+ console.log(err);
+ } else {
+ getUserInfo(email);
+ }
+ });
+
+ } else {
+ $(".oauth").show(500);
+ $("#consumer_key").val(email)
+ $("#consumer_secret").val(doc.oauth.consumer_keys[email]);
+ $("#token_secret").val(doc.oauth.tokens.node_sign_token);
+ }
+}
+
+function getSigningInfo(email, doc) {
+ if (doc.lrsignature && doc.lrsignature.full_name) {
+ $("#full_name").val(doc.lrsignature.full_name);
+ }
+}
+
+function setMessage(msg, wait, cb) {
+ if (!wait) {
+ wait = 10000;
+ }
+
+ $(".msg").fadeOut('fast').empty().text(msg).fadeIn('fast').delay(wait).fadeOut('slow').hide('fast');
+
+ if (cb) {
+ cb();
+ }
+}
+
+function setSigningInfo() {
+ full_name = $("#full_name").val();
+ if ($.trim(full_name) !== "") {
+ session.info(function(err, session_info){
+ if (session_info.userCtx.name) {
+ users.get(session_info.userCtx.name, function(err, doc){
+ doc.lrsignature = doc.lrsignature || {}
+ doc.lrsignature.full_name = full_name;
+
+ users.update(session_info.userCtx.name, null, doc, function(err) {
+ if (err) {
+ console.log(err);
+ setMessage("Unable to save signing information.");
+ } else {
+ setMessage("Information saved.")
+ }
+ });
+ });
+ };
+ });
+ }
+}
+
+function getUserInfo(email) {
+ users.get(email, function(err, doc) {
+ if (!err) {
+ getOAuth(email, doc);
+ getSigningInfo(email, doc);
+ }
+ else {
+ setMessage(err);
+ }
+ });
+}
+
+function revokeAndGenerate() {
+ session.info(function(err, session_info){
+ if (session_info.userCtx.name) {
+ users.get(session_info.userCtx.name, function (err, doc){
+ if (!err) {
+ getOAuth(session_info.userCtx.name, doc, true);
+ }
+ });
+ } else {
+ sessionTimeout();
+ }
+ });
+}
+
+function sessionTimeout () {
+ setMessage("Session has timed out.", 50000, function(){
+ window.location.reload();
+ });
+}
+
+
+exports.registerCallbacks = function() {
+ $.couch.browserid.login(function(evt, err, info) {
+ try {
+ if (info && info.email) {
+ console.log(info.email);
+ getUserInfo(info.email);
+ }
+ } catch (error) {
+
+ } finally {
+
+ }
+ });
+
+ $.couch.browserid.logout(function(evt, err, info){
+ window.location.reload();
+ });
+
+ $("#info_update").bind('click', setSigningInfo);
+ $("#regenerate").bind('click', revokeAndGenerate);
+}
+
+
+// Simple secret key generator
+exports.generateSecret = function(length) {
+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ var secret = '';
+ for (var i = 0; i < length; i++) {
+ secret += tab.charAt(Math.floor(Math.random() * 64));
+ }
+ return secret;
+}
+
View
11 couchdb/apps/kanso/restrict-writers/kanso.json
@@ -0,0 +1,11 @@
+{
+ "name": "restrict-writers",
+ "version": "0.0.1",
+ "description": "Restrict writers to lrnode role",
+ "modules":["lib"],
+ "load":"lib/app",
+ "dependencies": {
+ "modules":null,
+ "properties": null
+ }
+}
View
52 couchdb/apps/kanso/restrict-writers/lib/app.js
@@ -0,0 +1,52 @@
+exports.validate_doc_update =
+ function(newDoc, oldDoc, userCtx, secObj) {
+ if (newDoc._deleted === true) {
+ // allow deletes by admins and matching users
+ // without checking the other fields
+ if ((userCtx.roles.indexOf('_admin') !== -1) ||
+ (userCtx.name == oldDoc.name)) {
+ return;
+ } else {
+ throw({forbidden: 'Only admins may delete other user docs.'});
+ }
+ }
+
+
+ var is_server_or_database_admin = function(userCtx, secObj) {
+ // see if the user is a server admin
+ if(userCtx.roles.indexOf('_admin') !== -1) {
+ return true; // a server admin
+ }
+
+ // see if the user a database admin specified by name
+ if(secObj && secObj.admins && secObj.admins.names) {
+ if(secObj.admins.names.indexOf(userCtx.name) !== -1) {
+ return true; // database admin
+ }
+ }
+
+ // see if the user a database admin specified by role
+ if(secObj && secObj.admins && secObj.admins.roles) {
+ var db_roles = secObj.admins.roles;
+ for(var idx = 0; idx < userCtx.roles.length; idx++) {
+ var user_role = userCtx.roles[idx];
+ if(db_roles.indexOf(user_role) !== -1) {
+ return true; // role matches!
+ }
+ }
+ }
+
+ return false; // default to no admin
+ }
+
+ if (!is_server_or_database_admin(userCtx, secObj)) {
+ if (newDoc) {
+ throw({
+ forbidden: 'Only server or db admin can modify this db.'
+ });
+ }
+ }
+
+
+
+ }

0 comments on commit fcfb697

Please sign in to comment.