Git Product home page Git Product logo

stormpath-node-config's Introduction

#Stormpath is Joining Okta We are incredibly excited to announce that Stormpath is joining forces with Okta. Please visit the Migration FAQs for a detailed look at what this means for Stormpath users.

We're available to answer all questions at [email protected].

stormpath-node-config

Stormpath configuration loader.

NPM Version NPM Downloads Build Status Coverage Status

This library is responsible for loading the Stormpath configuration. It is an internal module used by stormpath-node-sdk, and express-stormpath, and is not meant for general consumption.

Installation

To install this library, just run:

$ npm install stormpath-config --save

Usage

First, start by including the library:

var stormpathConfig = require('stormpath-config');

Once the library is loaded, you'll need to initialize a new Loader object using the library like so:

var configLoader = new stormpathConfig.Loader([/* strategies */]);

Notice how the first argument is commented out. This needs to be an array of one or many strategies. See strategies for a list of all supported strategies and on how to create your own.

E.g. below demonstrates how the Stormpath configuration can be created and loaded from only the environment.

var strategy = stormpathConfig.strategy;

var configLoader = new StormpathConfig.Loader([
    new strategy.LoadEnvConfigStrategy(),
    new strategy.LoadFileConfigStrategy('~/stormpath.yml')
]);

Now, once you got your new Loader object all you need to do is call the configLoader.load(callback) method to load the configuration data. You can do this like so:

configLoader.load(function (err, config) {
  if (err) {
    console.error(err);
  } else {
    console.log("Configuration loaded:", config);
  }
});

Strategies

Creating your own strategy

A strategy is simply a prototype that implements a method named process that takes the parameters config and callback. All it expects is that the callback is called with the first argument as an error (null if none) and the second containing the modified/processed config. E.g. as shown below:

function MyConfigStrategy () {
}

MyConfigStrategy.prototype.process = function (config, callback) {
  // Apply strategy to config and return result in callback
  config.someNewField = "abc"; // Append someNewField to our config
  callback(null, config);
};

Supported

Some default strategies for loading a configuration has been included. These are accessible through the strategy export. I.e. require('stormpath-config').strategy.

LoadEnvConfigStrategy

Loads configuration from the system environment.

LoadAPIKeyConfigStrategy

Loads client API key configuration from a .properties file.

LoadFileConfigStrategy

Loads a configuration from either a JSON or YAML file.

ExtendConfigStrategy

Extend a the configuration with an existing object.

EnrichClientConfigStrategy

Enriches the configuration with client config resolved at runtime.

EnrichClientFromRemoteConfigStrategy

Enriches the configuration with client config resolved from the Stormpath API.

EnrichIntegrationConfigStrategy

Enriches the configuration with integration config resolved at runtime.

EnrichIntegrationFromRemoteConfigStrategy

Enriches the configuration with integration config resolved from the Stormpath API.

ValidateClientConfigStrategy

Validates the client configuration.

Resources

Below are some resources you might find useful:

Todo

  • Write unit tests.

Contributing

You can make your own contributions by forking this repository, making your changes in a feature branch, and then issuing a pull request back to this repository on the master branch.

Here's how you might do this if you wanted to contribute something:

$ git clone https://github.com/stormpath/stormpath-node-config.git
$ cd stormpath-node-config
$ git checkout -b feature-somthing-something
$ # make changes
$ git commit -m "This was easy!"
$ # submit a pull request

We regularly maintain this repository, and are quick to review pull requests and accept changes!

We <333 contributions!

Copyright

Copyright ©2015 Stormpath, Inc. and contributors.

This project is open-source via the Apache 2.0 License.

stormpath-node-config's People

Contributors

edjiang avatar greenkeeperio-bot avatar robertjd avatar timothyej avatar typerandom avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stormpath-node-config's Issues

postLoginHandler returns old data

Receiving an error with the email verification strategy, currently, the user account on stormpath is marked as enabled post verification, but the postLoginHandler in my app still has the status as UNVERIFIED

Bug in Loading Strategies

So, our Python contractor (@avojnovicDk) has been working on porting this library over to Python, and came across a bug in this code here: https://github.com/stormpath/stormpath-node-config/blob/master/lib/strategy/LoadAPIKeyConfigStrategy.js#L37-L39

So, here's what's happening. First, take a look at the order in which things are supposed to be loaded from our sdk spec: https://github.com/stormpath/stormpath-sdk-spec/blob/master/specifications/config.md#loading-order

The order in which things should be loaded goes from most 'implicit' to most 'explicit'. So, the more explicit a user is about their settings, we'll prefer those explicit settings over the more generic ones. This makes sense, because it means a user will usually get what they expect in a magical way.

Here's the scenario in which the APIKeyConfigStrategy is broken:

Let's say I'm a user, and I have the following:

  • An API key file named ~/.stormpath/apiKey.properties,
  • An API key file named apiKey.properties inside of my local application folder that I'm currently working on.

Per our spec, we should first load the settings from ~/.stormpath/apiKey.properties, and later override it with the settings from apiKey.properties in the local directory since it also exists.

This is not happening though.

These lines of code: https://github.com/stormpath/stormpath-node-config/blob/master/lib/strategy/LoadAPIKeyConfigStrategy.js#L37-L39 show that if those API key values are already loaded from the first API key file, than we'll skip processing and use those old values INSTEAD of overwriting them like we should.

I think the solution is most likely to just remove these lines of code, but we should write some tests / etc. to cover this scenario first to make sure we aren't missing anything.

Unable to find apiKey.properties file when ~ is used

Fixes a issue where an API key wouldn't be loaded correctly from a home path.

How to reproduce

  1. Checkout the stormpath-config master branch.
  2. Execute $ npm link to make it available as a link.
  3. Create an empty test project folder (e.g. stormpath-config-test) and $ cd into it.
  4. Execute $ npm init --yes.
  5. Execute $ npm link stormpath-config so that we link to our stormpath-config master branch.
  6. Create a new file called app.js and put the contents of this gist in it.
  7. Create an apiKey.properties with the following content and put it in the ~/.stormpath/ directory.
  8. Run $ node app.js.

Actual

Console outputs:

[Error: Client API key file not found: /Users/orhedenr/.stormpath/apiKey.properties] undefined

Expected

Console outputs:

null { bob: 123, client: { apiKey: { id: 'abc', secret: 'def' } } }

YAML not working

The loader strategy for LoadFileConfigStrategy.js is not working correctly. It basically isn't picking up my stormpath.yml file in the main folder for my app. This seems to be because it isn't looking in the correct filepath for the stormpath.yml. There are 2ish main reasons/files associated for this(I think):

  1. File - ConfigLoader.js
    Function - ConfigLoader.prototype.load
    Line - 73) tasks.push(strategies[i].process.bind(strategies[i]));
  2. File - LoadFileConfigStrategy.js
    Function - LoadFileConfigStrategy.prototype.process
    Line - 24) var filePath = expandHomeDir(this.filePath);
    The base problem is that the filepath is not being expanded correctly(though i think expandHomeDir is doing what you want). I can't tell if this is because the state has been bound in an incorrect way or if the LoadFileConfigStrategy needs to do something different. There also seems to be some inconsistencies in the way things are used: for instance why check fs.exists(this.filePath) and then read from fs.readFile(filePath).

I also realize that this could all be correct and it's some async error i haven't accounted for.

Urgent: Don't Depend on HOME Being Set

2016-01-11T13:16:57.382Z    959bee10-b865-11e5-8b87-752e23b3a9b9    TypeError: Arguments to path.join must be strings at path.js:360:15 at Array.filter (native) at exports.join (path.js:358:36) at expandHomeDir (/var/task/node_modules/stormpath/node_modules/stormpath-config/node_modules/expand-home-dir/index.js:10:10) at new LoadAPIKeyConfigStrategy (/var/task/node_modules/stormpath/node_modules/stormpath-config/lib/strategy/LoadAPIKeyConfigStrategy.js:14:19) at module.exports (/var/task/node_modules/stormpath/lib/configLoader.js:17:5) at new Client (/var/task/node_modules/stormpath/lib/Client.js:43:45) at Response.<anonymous> (/var/task/stormpath_loader.js:21:26) at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:354:18) at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:105:20)

We need to modify our loading code to ensure that $HOME is not depended on -- this will ensure that our library works in environments where this variable isn't present (docker, AWS, etc.).

We need to get this fixed ASAP for a user.

cannot read property 'getGroup' of undefined.

When initializing the app with express-stormpath, it immediately fails with this error:

.../node_modules/express-stormpath/node_modules/stormpath-config/lib/strategy/EnrichIntegrationFromRemoteConfigStrategy.js:155
          outerScope.client.getGroup(href, function(err, group) {
                           ^

TypeError: Cannot read property 'getGroup' of undefined

Upon looking into it, it appears outerScope.client is never set in EnrichIntegrationFromRemoteConfigStrategy.js. In this context, outerScope is an alias for the Enrich instance. So by changing line 240 from

var client = this.clientFactory(config);

to

var client = this.client = this.clientFactory(config);

I was able to overcome the error. Is this a reasonable alteration? Or are we expecting that there is a client already on the Enrich... instance at that point?

Throw invalid config if `web.register.autoLogin` is true, while email verification is enabled

The property stormpath.web.register.autoLogin is false by default, but if the developer sets to true it means that we automatically create the Oauth2 cookies for the user after they register, an then redirect to the nextUri.

This is only possible if the email verification feature is disabled on the default account store of the specified application.

If the default account store has email verification enabled, and the developer defines autoLogin as true, we should throw an invalid configuration error:

Invalid configuration: stormpath.web.register.autoLogin is true, but the default account store of the specified application has the email verification workflow enabled. Auto login is only possible if email verification is disabled. Please disable this workflow on this application's default account store.

~/.stormpath/apiKey.properties is not loaded

Reproduction situation:

  • No environment variables are defined
  • The file ~/.stormpath/apiKey.properties does exist, with these contents:
apiKey.id = xxx
apiKey.secret = xxx

But the following construction fails:

var client  = new stormpath.Client();

With this error:

Error: API key ID and secret is required.

This may be a duplicate report of #6

"TypeError: undefined is not a function" if no default account store

Stacktrace:

TypeError: undefined is not a function
    at /Users/robert/projects/express-stormpath/node_modules/stormpath-config/lib/strategy/EnrichIntegrationFromRemoteConfigStrategy.js:149:9
    at Object.wrapGetResourceResponse [as _wrapGetResourceResponse] (/Users/robert/projects/express-stormpath/node_modules/stormpath/lib/ds/DataStore.js:67:12)
    at onGetResourceRequestResult (/Users/robert/projects/express-stormpath/node_modules/stormpath/lib/ds/DataStore.js:278:13)
    at Request.onRequestResult [as _callback] (/Users/robert/projects/express-stormpath/node_modules/stormpath/lib/ds/RequestExecutor.js:100:14)
    at Request.self.callback (/Users/robert/projects/express-stormpath/node_modules/request/request.js:198:22)
    at Request.emit (events.js:110:17)
    at Request.<anonymous> (/Users/robert/projects/express-stormpath/node_modules/request/request.js:1035:10)
    at Request.emit (events.js:129:20)
    at IncomingMessage.<anonymous> (/Users/robert/projects/express-stormpath/node_modules/request/request.js:962:12)
    at IncomingMessage.emit (events.js:129:20)

This happens when there is no default account store mapped to the specified application. This strategy should be modified to support the following situations:

  • If the application has 0 account stores mapped to it, we should provide the error "No account stores are mapped to the specified application. Account stores are required for login and registration"
  • If there is no default account store for the application, then:
    • If stormpath.web.register.enabled is true, then we should provide the error "No default account store is mapped to the specified application. A default account store is required for registration."
    • If stormpath.web.register.enabled is false, then we should not error. We should allow configuration parsing to continue, and the integration should be allowed to initialize. This is necessary because some applications provide login but not registration.

method are removed from cacheOptions.client

If you attempt to supply a cache client instance, like this:

var stormpath = require('stormpath');
var redis = require('redis');

var rc = redis.createClient();

var client = new stormpath.Client({
  cacheOptions: {
    store: 'redis',
    client: rc
  }
});

You will get this error:

/Users/robert/projects/nodeapp/node_modules/stormpath/lib/cache/RedisStore.js:26
  this.redis.get(key, function(err, entry){
             ^
TypeError: undefined is not a function
    at RedisStore.get (/Users/robert/projects/nodeapp/node_modules/stormpath/lib/cache/RedisStore.js:26:14)
    at Cache.get (/Users/robert/projects/nodeapp/node_modules/stormpath/lib/cache/Cache.js:52:14)
    at CacheHandler.getCachedResource [as get] (/Users/robert/projects/nodeapp/node_modules/stormpath/lib/cache/CacheHandler.js:91:51)
    at Object.executeRequest [as exec] (/Users/robert/projects/nodeapp/node_modules/stormpath/lib/ds/DataStore.js:294:22)
    at DataStore.getResource (/Users/robert/projects/nodeapp/node_modules/stormpath/lib/ds/DataStore.js:122:16)
    at Client.getResource (/Users/robert/projects/nodeapp/node_modules/stormpath/lib/Client.js:185:38)
    at Client.getApplication (/Users/robert/projects/nodeapp/node_modules/stormpath/lib/Client.js:514:15)
    at EnrichClientFromRemoteConfigStrategy._resolveApplicationByHref (/Users/robert/projects/nodeapp/node_modules/stormpath/node_modules/stormpath-config/lib/strategy/EnrichClientFromRemoteConfigStrategy.js:16:10)
    at Client.<anonymous> (/Users/robert/projects/nodeapp/node_modules/stormpath/node_modules/stormpath-config/lib/strategy/EnrichClientFromRemoteConfigStrategy.js:68:9)
    at Client.emit (events.js:107:17)

It seems that our object extension algorithm is stripping properties that are functions.

This problem happens during this extension:

https://github.com/stormpath/stormpath-node-config/blob/master/lib/strategy/ExtendConfigStrategy.js#L15

A quick fix would be this block of code, added after that extension:

if(this.extendWith.cacheOptions && this.extendWith.cacheOptions.client){
  config.cacheOptions.client = this.extendWith.cacheOptions.client;
}

@typerandom thoughts?

Add ability to debug loading process

Right now it's quite tedious to know exactly what has gone wrong in the loading process. For that reason we should add the ability to attach a logger that will output the configuration before each strategy is being executed. And once all strategies have exectued, it should also output the final result.

Suggestion

Setup
var strategies = [new FooConfigStrategy(), new BarConfigStrategy()];
var loader = new ConfigLoader(strategies, logger);
...

Where logger has a method called debug(). If a logger is provided it will always just call the debug method.

Console output
[Debug:BeforeStrategy] FooConfigStrategy:
{ abc: 123 }

[Debug:BeforeStrategy] BarConfigStrategy:
{ abc: 345 }

[Debug:FinalResult]:
{ abc: 567 }

Configuration is cleared when an empty apiKey.properties file is used

When an empty apiKey.properties file is used then all of the configuration is cleared.

How to reproduce

  1. Checkout the stormpath-config master branch.
  2. Execute $ npm link to make it available as a link.
  3. Create an empty test project folder (e.g. stormpath-config-test) and $ cd into it.
  4. Execute $ npm init --yes.
  5. Execute $ npm link stormpath-config so that we link to our stormpath-config master branch.
  6. Create a new file called app.js and put the contents of this gist in it.
  7. Execute $ touch apiKey.properties to create an empty apiKey.properties file.
  8. Run $ node app.js.

Actual

Console outputs:

null {}

Expected

Console outputs:

null { bob: 123 }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.