StrongLoop Node.js API Security & Customization

67
API SECURITY, CUSTOMIZATION, AND MOBILE BACKENDS Jordan Kasper | Developer Evangelist

Transcript of StrongLoop Node.js API Security & Customization

Page 1: StrongLoop Node.js API Security & Customization

API SECURITY, CUSTOMIZATION,AND MOBILE BACKENDS

Jordan Kasper | Developer Evangelist

Page 2: StrongLoop Node.js API Security & Customization

Open source REST API framework based on Express.js

Page 3: StrongLoop Node.js API Security & Customization
Page 4: StrongLoop Node.js API Security & Customization

LOOPBACK FEATURESModel-driven API developmentDynamic REST API endpoint generationConnect to any datasource (SQL, NoSQL, REST, SOAP)Rich model relationsAccess controls (built in token authentication)Geolocation, push notifications, offline syncAngular, Android, and iOS SDKs

Page 5: StrongLoop Node.js API Security & Customization

STEP 1: INSTALL STRONGLOOP TOOLS~$ npm install ­g strongloop

And scaffold your application:~$ slc loopback

Page 6: StrongLoop Node.js API Security & Customization

WORKING WITH DATA MODELS

Page 7: StrongLoop Node.js API Security & Customization

CREATING A MODEL VIA CLI~/my­app$ slc loopback:model[?] Enter the model name: CoffeeShop[?] Select the data­source to attach CoffeeShop to: (Use arrow keys)❯ mdb (mongodb)[?] Select model's base class: (Use arrow keys) Model❯ PersistedModel ACL[?] Expose CoffeeShop via the REST API? (Y/n) Y[?] Custom plural form (used to build REST URL):

Page 8: StrongLoop Node.js API Security & Customization

CREATING A MODEL VIA CLI[?] Property name: name invoke loopback:property[?] Property type: (Use arrow keys)❯ string number boolean object array date ...[?] Required? (y/N)

When complete, simply hit "enter" with a blank property

Page 9: StrongLoop Node.js API Security & Customization

MODEL CONFIG "name": "CoffeeShop", "base": "PersistedModel", "idInjection": true, "properties": "name": "type": "string", "required": true , "validations": [], "relations": , "acls": [], "methods": []

Page 10: StrongLoop Node.js API Security & Customization

RUN THE APPLICATION~/my­app$ node server/server.js

Web server's listening at http://localhost:3000Browse your REST API at http://localhost:3000/explorer

Page 11: StrongLoop Node.js API Security & Customization

COFFEESHOP ROUTEShttp://localhost:3000/api/CoffeeShops

[]

We don't have any coffee shops yet,so we get an empty array!

Page 12: StrongLoop Node.js API Security & Customization

http://localhost:3000/explorer

Page 13: StrongLoop Node.js API Security & Customization
Page 14: StrongLoop Node.js API Security & Customization
Page 15: StrongLoop Node.js API Security & Customization

RELATIONSHIP MODELING

Page 16: StrongLoop Node.js API Security & Customization

VARIOUS RELATIONSHIP TYPESHasManyHasManyThroughHasAndBelongsToManyPolymorphicEmbedded (embedsOne and embedsMany)

We also have a special "ownership" relation:"BelongsTo"

Page 17: StrongLoop Node.js API Security & Customization

RELATIONSHIP DEFINITION// common/models/coffee­shop.json "name": "CoffeeShop", // ..., "relations": "reviews": "type": "hasMany", "model": "Review"

Page 18: StrongLoop Node.js API Security & Customization

BELONGSTO RELATIONSHIPS (OWNERSHIP)// common/models/review.json "name": "Review", // ..., "relations": "reviewer": "type": "belongsTo", "model": "User"

Page 19: StrongLoop Node.js API Security & Customization

AUTHENTICATION ANDAUTHORIZATION

Page 20: StrongLoop Node.js API Security & Customization

LOOPBACK AUTH MODELSUserPrincipalRoleRoleMappingACL

Page 21: StrongLoop Node.js API Security & Customization

PRINCIPALSAn entity that can be identified or authenticated

A userA roleAn application

Page 22: StrongLoop Node.js API Security & Customization

ROLES AND MAPPINGSA Role is a group of principals with the same permissions.

RoleMappings are used to map principals onto Roles.

Page 23: StrongLoop Node.js API Security & Customization

DYNAMIC ROLESSome dynamic roles already exist for you:

$everyone (regardless of authorization status)$unauthenticated$authenticated$owner (using a belongsTo relation)

Page 24: StrongLoop Node.js API Security & Customization

CREATING NEW ROLES// server/boot/roles.jsmodule.exports = function(app)

app.models.Role.create(

name: 'admin'

, function(err, theAdminRole) if (err) cb(err);

// Maybe add some users to it? );

;

Page 25: StrongLoop Node.js API Security & Customization

ADDING USERS TO A CUSTOM ROLEtheAdminRole.principals.create(

principalType: app.models.RoleMapping.USER, principalId: someUser.id

, function(err, principal) // handle the error! cb(err););

Page 26: StrongLoop Node.js API Security & Customization

CUSTOM DYNAMIC ROLESUse Role.registerResolver() to set up a custom role handler:

// server/boot/roles.jsRole.registerResolver('admin', function(role, context, cb)

// custom method you create to determine this... determineAdminStatus(function(err, isAuthorized)

if (err) // maybe handle the error here? return cb(err);

// execute callback with a boolean cb(null, isAuthorized);

););

Page 27: StrongLoop Node.js API Security & Customization

ACCESS CONTROL LAYERSA layer defines what access a principal has for a certain

operation against a specific model.

Page 28: StrongLoop Node.js API Security & Customization

WHITELISTINGFor example, we might create these layers:

Deny everyone to access the modelAllow '$everyone' role to read instancesAllow '$authenticated' role to create instancesAllow '$owner' to update an existing instance

This is an example of "whitelisting", and is safer thandenying specific operations.

Page 29: StrongLoop Node.js API Security & Customization

DEFINING AN ACLWe use the slc loopback:acl subcommand:

~/my­app$ slc loopback:acl

Page 30: StrongLoop Node.js API Security & Customization

DEFINING AN ACLThe CLI will ask you some questions...

~/my­app$ slc loopback:acl? Select the model to apply the ACL entry to: CoffeeShop? Select the ACL scope: All methods and properties? Select the access type: All (match all types)? Select the role: All users? Select the permission to apply: Explicitly deny access

Page 31: StrongLoop Node.js API Security & Customization

DEFINING AN ACLNow allow everyone to read CoffeeShops:

~/my­app$ slc loopback:acl? Select the model to apply the ACL entry to: CoffeeShop? Select the ACL scope: All methods and properties? Select the access type: Read? Select the role: All users? Select the permission to apply: Explicitly grant access

Page 32: StrongLoop Node.js API Security & Customization

DEFINING AN ACLHere's what this looks like in the config file:

// in common/models/coffee­shop.json"acls": [ "accessType": "*", "principalType": "ROLE", "principalId": "$everyone", "permission": "DENY" , "accessType": "READ", "principalType": "ROLE", "principalId": "$everyone", "permission": "ALLOW" ]

Page 33: StrongLoop Node.js API Security & Customization

DEFINING ACLSAccess Control Layers execute in order, so be sure to DENY

first, then add all of your "whitelisting".

Page 34: StrongLoop Node.js API Security & Customization

USING OWNERSBy creating a belongsTo relation, we can use $owner :

"acls": [ // ..., "accessType": "WRITE", "principalType": "ROLE", "principalId": "$owner", "permission": "ALLOW" ]

Page 35: StrongLoop Node.js API Security & Customization

RESTRICTING SPECIFIC METHODSWe can ALLOW or DENY access to specific remote methods:"acls": [ // ..., "accessType": "EXECUTE", "principalType": "ROLE", "principalId": "admin", "permission": "ALLOW", "property": "create" ]

Page 36: StrongLoop Node.js API Security & Customization

ADVANCING YOUR API

Page 37: StrongLoop Node.js API Security & Customization

REMOTE METHODSA way to create new, non-CRUD methods on your model.

Page 38: StrongLoop Node.js API Security & Customization

REMOTE METHODSFirst, define the handler function...

// common/models/coffee­shop.jsmodule.exports = function(CoffeeShop)

CoffeeShop.status = function(id, cb) CoffeeShop.findById(id, function(err, shop) if (err) return cb(err);

cb( null, determineStatus() ); ); ;

// ...;

Page 39: StrongLoop Node.js API Security & Customization

REMOTE METHODSThen define the API spec...

// common/models/coffee­shop.jsmodule.exports = function(CoffeeShop)

CoffeeShop.status = function(id, cb) /* ... */

CoffeeShop.remoteMethod( 'status', accepts: [ arg: 'id', type: 'number', required: true, http: source: 'path' ], returns: arg: 'isOpen', type: 'boolean' , http: [ verb: 'get', path: '/:id/status' ] );;

Page 40: StrongLoop Node.js API Security & Customization

ACCESSING REMOTE METHODSA GET request to /api/CoffeeShops/1/status might return:

isOpen: true

Page 41: StrongLoop Node.js API Security & Customization

RESTRICTING REMOTE METHODSRemember, we can ALLOW or DENY access to specificremote methods on a model, including custom ones!

"acls": [ // ..., "accessType": "EXECUTE", "principalType": "ROLE", "principalId": "$unauthenticated", "permission": "DENY", "property": "status" ]

Page 42: StrongLoop Node.js API Security & Customization

GETTING THE CURRENT USERAt any point in your application you can get the current

user access token, and the user ID:// common/models/coffee­shop.js

var loopback = require('loopback');

module.exports = function(CoffeeShop)

CoffeeShop.status = function(id, cb) var context = loopback.getCurrentContext(); var token = context.get('accessToken');

console.log( 'Access Token ID', token.id ); console.log( 'Current User ID', token.userId ); ;

;

Page 43: StrongLoop Node.js API Security & Customization

CONNECTING TO THE FRONT ENDLoopBack has client SDKs for Angular, iOS, Android, and

Xamarin!

Page 44: StrongLoop Node.js API Security & Customization

STEP ONEThe first step is to generate the client code.

Here we use the Angular generator:~/my­app$ mkdir client/js/services

~/my­app$ lb­ng server/server.js client/js/services/lb­services.js

Page 45: StrongLoop Node.js API Security & Customization

ANGULAR MODELSLoopBack provides models for you to use in Angular which

have all of the remote methods ( create , find , destroy , etc).For User objects this includes the login() method!

Page 46: StrongLoop Node.js API Security & Customization

ANGULAR MODELSWhen you create your application modules, just include the

LoopBack Services we created from the CLI:angular.module('my­app', ['ui.router', 'lbServices'])

.config( ... )

.run( ... );

Page 47: StrongLoop Node.js API Security & Customization

CREATING AN AUTH SERVICENow we can create an Angular service for authentication:angular.module('my­app').factory( 'AuthService', ['User', '$q', '$rootScope', function(User, $q, $rootScope)

function login(email, password) return User .login( email: email, password: password ) .$promise .then(function(response) $rootScope.currentUser = id: response.user.id, tokenId: response.id ; );

return login: login ; ]);

Page 48: StrongLoop Node.js API Security & Customization

CREATING AN AUTH SERVICEThe logout() method is easy!

function logout() return User .logout() .$promise .then(function() $rootScope.currentUser = null; ); ;

Page 49: StrongLoop Node.js API Security & Customization

CREATING AN AUTH SERVICEWhen you use the User.login() method (and it is successful),

LoopBack will send an Authorization header with eachrequest containing the accessToken !

Page 50: StrongLoop Node.js API Security & Customization

USING 3RD PARTY AUTHIntegrating with 3rd party authentication services is easy!

Just use the .passport LoopBack component

Page 51: StrongLoop Node.js API Security & Customization

3RD PARTY AUTHThe basic workflow is:

1. Visitor clicks "login with X" button (i.e. Facebook (FB))2. LoopBack (LB) redirects to FB login page3. FB redirects to your LB server4. LB requests access token from FB5. LB uses token to get user info6. LB matches info to internal User model

(LB creates the user locally if it doesn't exist)7. User info is added to the LB context

Page 52: StrongLoop Node.js API Security & Customization

3RD PARTY AUTHFirst, install the passport component:

~/my­app$ npm install ­­save loopback­component­passport

Then set up a PassportConfigurator ...(This is the piece that connects LoopBack to Passport.)

Page 53: StrongLoop Node.js API Security & Customization

CONFIGURING PASSPORTWe need to configure Passport, a boot script works:

// server/boot/setup­auth.jsvar loopback = require('loopback'), PPConfigurator = require('loopback­component­passport').PassportConfigurator;

module.exports = function(app) // Enable http sessions app.use(loopback.session( secret: 'super­secret­string' ));

var configurator = new PPConfigurator(app); configurator.init(); configurator.setupModels( userModel: app.models.user, userIdentityModel: app.models.userIdentity, userCredentialModel: app.models.userCredential );

configurator.configureProvider('facebook­login', // ... );;

Page 54: StrongLoop Node.js API Security & Customization

CONFIGURING PASSPORTAnd here is our Facebook-specific config...

// server/boot/setup­auth.js

...module.exports = function(app) // ...

configurator.configureProvider('facebook­login', provider: 'facebook', module: 'passport­facebook', clientID: 'your­FB­client­id', clientSecret: 'your­FB­client­secret', callbackURL: 'http://localhost:3000/auth/facebook/callback', authPath: '/auth/facebook', callbackPath: '/auth/facebook/callback', successRedirect: '/auth/account', scope: ['email'] );;

Page 55: StrongLoop Node.js API Security & Customization

ADDITIONAL PASSPORT STEPSFill in your FB/Google/etc app detailsCreate a UI button linking to /auth/facebookSet up a page at /auth/account (or wherever successRedirectpoints)Add other auth providers!

See an example app here:https://github.com/strongloop/loopback-example-passport

Page 56: StrongLoop Node.js API Security & Customization

BEING AN OAUTH PROVIDERWant to be your own OAuth provider?

(instead of using Facebook, Google, etc)

Page 57: StrongLoop Node.js API Security & Customization

BEING AN OAUTH PROVIDERYou can use StrongLoop's !oauth2 LoopBack component~/my­app$ npm install ­­save loopback­coponent­oath2

* Note that this component requires a license.

Page 58: StrongLoop Node.js API Security & Customization

CONFIGURE OAUTH// server/boot/oauth.js

var oauth2 = require('loopback­component­oauth2');

module.exports = function(app)

oauth2.oAuth2Provider( app, dataSource': app.dataSources.mydb, authorizePath': '/oauth/authorize', loginPage': '/login', loginPath': '/login' );

;

Full options can be found on docs.strongloop.com

Page 59: StrongLoop Node.js API Security & Customization

OAUTH LOGINDon't forget that you still need to code the login page!

And you will also need a callback URL for the authorizationaction.

Page 60: StrongLoop Node.js API Security & Customization

OAUTH LOCK DOWNNow we configure the resource endpoints we're locking

down:// server/middleware.json

"auth": "loopback­component­oauth2#authenticate": "paths": [ "/api" ], "params": "session": false, "scopes": "reviews": [ "/api/Reviews" ], "user": [ "methods": ["find", "findById", "destroy", "save"], "path": "/api/Users" ]

Page 61: StrongLoop Node.js API Security & Customization

WHAT ABOUT RATE LIMITING AND PROXY?Create more middleware at specific phases.

Capture the request and evaluate before passing it on.Centralized in front of your resource server!

Page 62: StrongLoop Node.js API Security & Customization

DEMO PROJECThttps://github.com/jakerella/lb-central

You can use this demo project as a starting point:~$ git clone https://github.com/jakerella/lb­central.git

~$ cd lb­central && npm install

NOTE: This code is licensed by StrongLoop, you will need a license to use it!

Page 63: StrongLoop Node.js API Security & Customization

RATE LIMITING YOUR APIControl how many requests a client can

make within a time period.Simply add the middleware config!

Page 64: StrongLoop Node.js API Security & Customization

CONFIGURE RATE LIMITING"routes:after": "./middleware/rate­limiting": "params": "interval": 60000, "keys": "ip": 100, "url": "template": "url­$urlPaths[0]/$urlPaths[1]", "limit": 500 , "user": "template": "user­$user.id", "limit": 1500 , "app,user": "template": "app­$app.id­user­$user.id", "limit": 2500

Page 65: StrongLoop Node.js API Security & Customization

REQUEST PROXIESOnce the the user is authenticated, rate limiting is

compelte, and any other centralized code, we can proxyrequests to their final destination.

Page 66: StrongLoop Node.js API Security & Customization

PROXYING REQUESTSSend requests from this server to the resource server(s):// in middleware.json

"routes:after": "./middleware/proxy": "params": "rules": [ "/api/foo/(.*)$ https://service­one.com:3007/api/$1 [P]", "/api/bar/(.*)$ https://service­two.com:3001/api/v2/$1 [P]" ]

Page 67: StrongLoop Node.js API Security & Customization

THANK YOU!QUESTIONS?

Jordan Kasper | Developer EvangelistJoin us for more events!

strongloop.com/developers/events