Updates for ODL Neon
[ccsdk/distribution.git] / dgbuilder / red / nodes / credentials.js
1 /**
2  * Copyright 2014 IBM Corp.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  **/
16
17 var util = require("util");
18 var when = require("when");
19
20 var credentialCache = {};
21 var storage = null;
22 var credentialsDef = {};
23 var redApp = null;
24
25 /**
26  * Adds an HTTP endpoint to allow look up of credentials for a given node id.
27  */
28 function registerEndpoint(type) {
29     redApp.get('/credentials/' + type + '/:id', function (req, res) {
30         // TODO: This could be a generic endpoint with the type value
31         //       parameterised.
32         //
33         // TODO: It should verify the given node id is of the type specified -
34         //       but that would add a dependency from this module to the
35         //       registry module that knows about node types.
36         var nodeType = type;
37         var nodeID = req.params.id;
38
39         var credentials = credentialCache[nodeID];
40         if (credentials === undefined) {
41             res.json({});
42             return;
43         }
44         var definition = credentialsDef[nodeType];
45
46         var sendCredentials = {};
47         for (var cred in definition) {
48             if (definition.hasOwnProperty(cred)) {
49                 if (definition[cred].type == "password") {
50                     var key = 'has_' + cred;
51                     sendCredentials[key] = credentials[cred] != null && credentials[cred] !== '';
52                     continue;
53                 }
54                 sendCredentials[cred] = credentials[cred] || '';
55             }
56         }
57         res.json(sendCredentials);
58
59     });
60 }
61
62
63 module.exports = {
64     init: function (_storage) {
65         storage = _storage;
66         // TODO: this should get passed in init function call rather than
67         //       required directly.
68         redApp = require("../server").app;
69     },
70     
71     /**
72      * Loads the credentials from storage.
73      */
74     load: function () {
75         return storage.getCredentials().then(function (creds) {
76             credentialCache = creds;
77         }).otherwise(function (err) {
78             util.log("[red] Error loading credentials : " + err);
79         });
80     },
81     
82     /**
83      * Adds a set of credentials for the given node id.
84      * @param id the node id for the credentials
85      * @param creds an object of credential key/value pairs
86      * @return a promise for the saving of credentials to storage
87      */
88     add: function (id, creds) {
89         credentialCache[id] = creds;
90         return storage.saveCredentials(credentialCache);
91     },
92
93     /**
94      * Gets the credentials for the given node id.
95      * @param id the node id for the credentials
96      * @return the credentials
97      */
98     get: function (id) {
99         return credentialCache[id];
100     },
101
102     /**
103      * Deletes the credentials for the given node id.
104      * @param id the node id for the credentials
105      * @return a promise for the saving of credentials to storage
106      */
107     delete: function (id) {
108         delete credentialCache[id];
109         storage.saveCredentials(credentialCache);
110     },
111
112     /**
113      * Deletes any credentials for nodes that no longer exist
114      * @param getNode a function that can return a node for a given id
115      * @return a promise for the saving of credentials to storage
116      */
117     clean: function (getNode) {
118         var deletedCredentials = false;
119         for (var c in credentialCache) {
120             if (credentialCache.hasOwnProperty(c)) {
121                 var n = getNode(c);
122                 if (!n) {
123                     deletedCredentials = true;
124                     delete credentialCache[c];
125                 }
126             }
127         }
128         if (deletedCredentials) {
129             return storage.saveCredentials(credentialCache);
130         } else {
131             return when.resolve();
132         }
133     },
134     
135     /**
136      * Registers a node credential definition.
137      * @param type the node type
138      * @param definition the credential definition
139      */
140     register: function (type, definition) {
141         var dashedType = type.replace(/\s+/g, '-');
142         credentialsDef[dashedType] = definition;
143         registerEndpoint(dashedType);
144     },
145     
146     /**
147      * Extracts and stores any credential updates in the provided node.
148      * The provided node may have a .credentials property that contains
149      * new credentials for the node.
150      * This function loops through the credentials in the definition for
151      * the node-type and applies any of the updates provided in the node.
152      * 
153      * This function does not save the credentials to disk as it is expected
154      * to be called multiple times when a new flow is deployed.
155      *
156      * @param node the node to extract credentials from
157      */
158     extract: function(node) {
159         var nodeID = node.id;
160         var nodeType = node.type;
161         var newCreds = node.credentials;
162         if (newCreds) {
163             var savedCredentials = credentialCache[nodeID] || {};
164             
165             var dashedType = nodeType.replace(/\s+/g, '-');
166             var definition = credentialsDef[dashedType];
167             
168             if (!definition) {
169                 util.log('Credential Type ' + nodeType + ' is not registered.');
170                 return;
171             }
172             
173             for (var cred in definition) {
174                 if (definition.hasOwnProperty(cred)) {
175                     if (newCreds[cred] === undefined) {
176                         continue;
177                     }
178                     if (definition[cred].type == "password" && newCreds[cred] == '__PWRD__') {
179                         continue;
180                     }
181                     if (0 === newCreds[cred].length || /^\s*$/.test(newCreds[cred])) {
182                         delete savedCredentials[cred];
183                         continue;
184                     }
185                     savedCredentials[cred] = newCreds[cred];
186                 }
187             }
188             credentialCache[nodeID] = savedCredentials;
189         }
190     },
191     
192     /**
193      * Saves the credentials to storage
194      * @return a promise for the saving of credentials to storage
195      */
196     save: function () {
197         return storage.saveCredentials(credentialCache);
198     },
199     
200     /**
201      * Gets the credential definition for the given node type
202      * @param type the node type
203      * @return the credential definition
204      */
205     getDefinition: function (type) {
206         return credentialsDef[type];
207     }
208 }