building a wifi hotspot with nodejs: cisco meraki - excap api

52
Building a WiFi Hotspot with NodeJS Cisco Meraki – ExCap API Cory Guynn, Consulting Systems Engineer DEVNET-2049

Upload: cisco-devnet

Post on 08-Feb-2017

550 views

Category:

Technology


4 download

TRANSCRIPT

Building a WiFi Hotspot with NodeJS Cisco Meraki – ExCap API

Cory Guynn, Consulting Systems EngineerDEVNET-2049

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 2DEVNET-2049

Cisco MerakiCloud Managed IT

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 3DEVNET-2049

Captive Portal

SplashBranding, T&Cs, advertising, survey

AuthenticationProcess login

LogStore session and form data

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 4DEVNET-2049

Meraki Splash Page Options

BrandingSurveyT&Cs

Click-through Sign-on

“Splash, agree, have a nice day” “Splash, register/login, have a nice day”

BrandingRADIUS w/ COALogout

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 5DEVNET-2049

Meraki Dashboard

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 6DEVNET-2049

Access Control

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 7DEVNET-2049

Walled Garden

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 8DEVNET-2049

Custom Splash URL

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 9DEVNET-2049

NodeJSBuilding the Webservice

• JavaScript with I/O

• Active developer community

• Rich library with NPM (Node Package Modules)

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 10DEVNET-2049

Install Sample AppInstall NodeJS

Install MongoDB

Clone source code

git clone https://github.com/dexterlabora/excap.git

or

git clone https://github.com/dexterlabora/excap-social.git

Install dependencies (while in root of the cloned directory)

npm install

Run application

node app.js

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 11DEVNET-2049

NodeJS Required Modules

• express• Web server framework

• express-session• Store client session data

• mongodb• No-SQL database

• handlebars• HTML template framework

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 12DEVNET-2049

Web Services

Express

var express = require('express')var app = express() app.get('/', function (req, res) { res.send('Hello World')}) app.listen(3000)

“Fast, unopinionated, minimalist web framework”

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 13DEVNET-2049

Web Services

app.use(require('express-session')({ secret: 'supersecret', // this secret is used to encrypt cookie cookie: { maxAge: 1000 * 60 * 60 * 24 // 1 day }, store: store, resave: true, saveUninitialized: true}));

Express-SessionSession data is not saved in the cookie itself, just the session ID. Session data is stored server-side.

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 14DEVNET-2049

Web Services

var MongoDBStore = require('connect-mongodb-session')(session);

var store = new MongoDBStore({ uri: 'mongodb://localhost:27017/test', collection: 'excap'});

MongoDBStore session data into a No-SQL database

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 15DEVNET-2049

Click-through Splash Page

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 16DEVNET-2049

Click-through Network Flow

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 17DEVNET-2049

Click-through Code FlowApp

Web ServicesRoutes

MongoDB

Express[get] /click

[post] /login

[get] /success

Meraki

HTML

success.hbs

continue_url/success

HTML

click-through.hbs

authbase_grant_url

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 18DEVNET-2049

Click-through ExCap APIMeraki Provided Information

• base_grant_url• https://n143.network-auth.com/splash/grant

• user_continue_url

• node_mac

• client_ip

• client_mac

• ap_name

• ap_tags

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 19DEVNET-2049

Request from Meraki via client

http://app.internetoflego.com:1880/click?base_grant_url=https%3A%2F%2Fn143.network-auth.com%2Fsplash%2Fgrant&user_continue_url=http%3A%2F%2Fwww.ask.com%2F&node_id=149624927555708&node_mac=88:15:44:a8:10:7c&gateway_id=149624927555708&client_ip=10.223.205.118&client_mac=84:3a:4b:50:e2:3c

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 20DEVNET-2049

/click// serving the static click-through HTML fileapp.get('/click', function (req, res) {

// extract parameters (queries) from URL req.session.host = req.headers.host; req.session.base_grant_url = req.query.base_grant_url; req.session.user_continue_url = req.query.user_continue_url; req.session.node_mac = req.query.node_mac; req.session.client_ip = req.query.client_ip; req.session.client_mac = req.query.client_mac; req.session.splashclick_time = new Date().toString();

// success page options instead of continuing on to intended url req.session.success_url = 'http://' + req.session.host + "/success"; req.session.continue_url = req.query.user_continue_url;

// display session data for debugging purposes console.log("Session data at click page = " + util.inspect(req.session, false, null));

// render login page using handlebars template and send in session data res.render('click-through', req.session);

});

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 21DEVNET-2049

Click-through.hbs{{handlebars}}

<div id="continue"> <h1>IoL Cafe</h1> <p>Please enjoy our complimentary WiFi and a cup of joe.</p> <p> Brought to you by <a href="http://www.internetoflego.com" target="blank">InternetOfLego.com</a> </p> <form action="/login" method="post" class="form col-md-12 center-block"> <div class="form-group"> <input class="form-control input-lg" placeholder="Email" type="text" name="form1[email]" required> </div>

<div class="form-group"> <button class="btn btn-primary btn-lg btn-block">Sign In</button> <span class="pull-left"><a href="#">Terms and Conditions</a></span>

</div> </form> </div> </div> <div class="footer"> <p>Your IP: {{client_ip}}</p> <p>Your MAC: {{client_mac}}</p> <p>AP MAC: {{node_mac}}</p> <h3>POWERED BY</h3> <img class="text-center" src="/img/cisco-meraki-gray.png" style="width:10%; margin:10px;"> </div>

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 22DEVNET-2049

Process Login// handle form submit button and send data to Cisco Meraki - Click-throughapp.post('/login', function(req, res){

// save data from HTML form req.session.form = req.body.form1; req.session.splashlogin_time = new Date().toString();

// forward request onto Cisco Meraki to grant access // *** Send user to success page : success_url res.writeHead(302, {

'Location': req.session.base_grant_url + "? continue_url="+req.session.success_url }); res.end();});

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 23DEVNET-2049

Success!Session Log Data

excap-1 Session data at login page = { cookie:excap-1    { path: '/',excap-1      _expires: Mon Dec 07 2015 02:11:55 GMT+0000 (UTC),excap-1      originalMaxAge: 604800000,excap-1      httpOnly: true,excap-1      secure: null,excap-1      domain: null },excap-1  host: ’127.0.0.1:8181',excap-1  base_grant_url: 'https://n143.network-auth.com/splash/grant',excap-1  user_continue_url: 'http://www.google.com/',excap-1  node_mac: '00:18:0a:13:dd:b0',excap-1  client_ip: '10.173.154.6',excap-1  client_mac: 'f8:95:c7:ff:86:27',excap-1  splashclick_time: 'Mon Nov 30 2015 02:11:54 GMT+0000 (UTC)',excap-1  _locals: {}, excap-1  form: { email: '[email protected]' },

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 25DEVNET-2049

Click-through w/Social Login

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 26DEVNET-2049

Code OverviewClick-through with Social OAuth

App

Web Services

Routes

MongoDB

Express

[get] /click

[get] /auth/google

[get] /success

Meraki

HTMLsuccess.hbs continue_url

/success

HTML

click-through.hbs

auth

[get] /auth/wifi

passport strategy

Social OAuth

success callback/auth/wifi

OAuth

base_grant_url

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 27DEVNET-2049

OAuth

“Simple, unobtrusive authentication for Node.js"

Passport is authentication middleware for Node.js. Extremely flexible and modular, Passport can be unobtrusively dropped in to any Express-based web application. A comprehensive set of strategies support authentication using a username and password, Facebook, Twitter, and more.

http://passportjs.org/

Passport

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 28DEVNET-2049

click-through.hbs

<div> <h3>Login Options</h3>

<a href="/auth/signup" class="btn btn-default"><span class="fa fa-user"></span> Email</a> <a href="/auth/facebook" class="btn btn-primary"><span class="fa fa-facebook"></span> Facebook</a> <a href="/auth/twitter" class="btn btn-info"><span class="fa fa-twitter"></span> Twitter</a> <a href="/auth/google" class="btn btn-danger"><span class="fa fa-google-plus"></span> Google+</a> <a href="/auth/linkedin" class="btn btn-info"><span class="fa fa-linkedin"></span> LinkedIn</a> </div>

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 29DEVNET-2049

/auth/google

// send to google to do the authenticationapp.get('/auth/google', passport.authenticate('google'));

// the callback after google has authenticated the userapp.get('/auth/google/callback', passport.authenticate('google', { successRedirect : '/auth/wifi', failureRedirect : '/auth/google' }));

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 30DEVNET-2049

Passport Strategy

var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;

passport.use(new GoogleStrategy({ clientID : configAuth.googleAuth.clientID, clientSecret : configAuth.googleAuth.clientSecret, callbackURL : configAuth.googleAuth.callbackURL, scope : ['profile', 'email'], passReqToCallback : true }, function(req, token, refreshToken, profile, done) {

... SNIP ...

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 31DEVNET-2049

Google API

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 32DEVNET-2049

/auth/wifi

// authenticate wireless session with Cisco Merakiapp.get('/auth/wifi', function(req, res){ req.session.splashlogin_time = new Date().toString();

// debug - monitor : display all session data on console console.log("Session data at login page = " + util.inspect(req.session, false, null)); // *** redirect user to Meraki to process authentication, then send client to success_url res.writeHead(302, {'Location': req.session.base_grant_url + "?continue_url="+req.session.success_url}); res.end();});

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 33DEVNET-2049

Google Login

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 35DEVNET-2049

Sign-on Splash Page

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 36DEVNET-2049

Sign-on Flow

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 37DEVNET-2049

Code OverviewSign-on

App

HTMLWeb ServicesRoutes

Signon.hbs

MongoDB

Express[get]

/signon

[get] /success

[get] /logout

Meraki

RADIUS

HTML

success.hbslogout.hbs

redirect to/success

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 38DEVNET-2049

ExCap APISign-on

• login_url• https://n143.network-auth.com/splash/login?mauth

=MMtoqbXZbiYvY2dkMWlEV06tIgp9mo6qkQKKcHG-0Oj4kb2bW0Vu4dLljkScAJRft95MSEA0YFLalbkUQtkt0YuL8jr_aRKOORUrbO8r8Vwq4EyRq9kfpkP2usCJL5qXRX7yrUCWtRyW0ryhTzs3lz6Gi2RVENFDo_vukBWh2Dcvso4AAl-mJJ2c8KaEnFlFCYS-gPn4ZhDA8&continue_url=http%3A%2F%2Fconnectivitycheck.android.com%2Fgenerate_204

• continue_url

• node_mac

• client_ip

• client_mac

• ap_name

• ap_tags

• logout_url

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 39DEVNET-2049

/signonapp.get('/signon', function (req, res) {

// extract parameters (queries) from URL req.session.host = req.headers.host; req.session.login_url = req.query.login_url; req.session.continue_url = req.query.continue_url; req.session.ap_name = req.query.ap_name; req.session.ap_tags = req.query.ap_tags; req.session.client_ip = req.query.client_ip; req.session.client_mac = req.query.client_mac; req.session.success_url = req.protocol + "://" + req.session.host + "/success"; req.session.signon_time = new Date();

// render login page using handlebars template and send in session data res.render('sign-on', req.session);

});

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 40DEVNET-2049

sign-on.hbs{{handlebars}}

<form action={{login_url}} method="post" class="form col-md-12 center-block"> <input type="hidden" name="success_url" value={{success_url}} /> <div class="form-group"> <div class="error"> {{recent_error}} </div> <input class="form-control input-lg" type="text" name="username" placeholder="Username or email"> <i class="icon-user icon-large"></i> </div> <div class="form-group"> <input class="form-control input-lg" type="password" name="password" placeholder="Password"> <i class="icon-lock icon-large"></i> </div>

<div class="form-group"> <button class="btn btn-primary btn-lg btn-block">Sign In</button> <span class="pull-left"><a href="#">Terms and Conditions</a></span>... snip … <div class="footer"> <p>Client IP: {{client_ip}}</p> <p>Client MAC: {{client_mac}}</p> <p>AP Tags: {{ap_tags}}</p> <p>AP Name: {{ap_name}}</p> <p>AP MAC: {{node_mac}}</p>

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 41DEVNET-2049

/success

app.get('/success', function (req, res) {

// extract parameters (queries) from URL req.session.host = req.headers.host; req.session.logout_url = req.query.logout_url + "&continue_url=" + req.protocol + "://" + req.session.host + "/logout"; req.session.success_time = new Date();

// render sucess page using handlebars template and send in session data res.render('success', req.session);});

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 42DEVNET-2049

Success!

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 43DEVNET-2049

/logoutapp.get('/logout', function (req, res) {

// determine session duration req.session.loggedout_time = new Date(); req.session.duration = {}; req.session.duration.ms = Math.abs(req.session.loggedout_time - req.session.success_time) ; req.session.duration.sec = Math.floor((req.session.duration.ms/1000) % 60); req.session.duration.min = (req.session.duration.ms/1000/60) << 0;

// extract parameters (queries) from URL req.session.host = req.headers.host; req.session.logout_url = req.query.logout_url + "&continue_url=" + req.protocol + "://" + req.session.host + "/logged-out";

// render sucess page using handlebars template and send in session data res.render('logged-out', req.session);});

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 44DEVNET-2049

Logged Out

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 45DEVNET-2049

Resources

Meraki Developers Portalhttp://developers.meraki.com/

Cory GuynnTwitter: @eedionysusEmail: [email protected]

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 46DEVNET-2049

Resources

• Captive Portal Solution Guide• https://meraki.cisco.com/lib/pdf/meraki_whitepaper_captive_portal.pdf

• Write-ups and source code• ExCap

• http://www.internetoflego.com/wifi-hotspot-cisco-meraki-excap-nodejs/• https://github.com/dexterlabora/excap• Node-RED version

• http://flows.nodered.org/flow/e80275ccd499c2edaf43

• ExCap-Social• http://www.internetoflego.com/wifi-hotspot-with-social-oauth-passport-mongodb/• https://github.com/dexterlabora/excap-social

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 47DEVNET-2049

Install Sample App

Install NodeJS

Install MongoDB

Clone source code

git clone https://github.com/dexterlabora/excap.git

or

git clone https://github.com/dexterlabora/excap-social.git

Install dependencies (while in root of the cloned directory)

npm install

Run application

node app.js

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 48DEVNET-2049

logged-out.hbs

<h1>Logged Out!</h1> <p> Total session duration: {{duration.min}} minutes {{duration.sec}} seconds </p> </div> </div>

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public

Complete Your Online Session Evaluation

Don’t forget: Cisco Live sessions will be available for viewing on-demand after the event at CiscoLive.com/Online

• Give us your feedback to be entered into a Daily Survey Drawing. A daily winner will receive a $750 Amazon gift card.

• Complete your session surveys through the Cisco Live mobile app or from the Session Catalog on CiscoLive.com/us.

49DEVNET-2049

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 50DEVNET-2049

Continue Your Education• Demos in the Cisco campus

• Walk-in Self-Paced Labs

• Lunch & Learn

• Meet the Engineer 1:1 meetings

• Related sessions

Thank you

© 2016 Cisco and/or its affiliates. All rights reserved. Cisco Public 51DEVNET-2049