diff --git a/.gitignore b/.gitignore index 0760e7c..1e6dccd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ dist app/bower_components coverage .env +*.log +kill_ez_dev.pids diff --git a/Gruntfile.js b/Gruntfile.js index ef0d491..0bc4ac0 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -80,7 +80,6 @@ module.exports = function (grunt) { }, livereload: { options: { - open: 'http://<%=hostname %>:<%=port %>', base: [ '.tmp', '<%= yeoman.app %>' diff --git a/README.md b/README.md index 62530cf..49b7b52 100644 --- a/README.md +++ b/README.md @@ -6,20 +6,19 @@ intuitive API and expert support make it easy for developers to authenticate, manage, and secure users and roles in any application. This is the development environment for the Stormpath hosted ID Site. You can -use this repository to build the same single page application (SPA) that -Stormpath provides by default. The SPA uses Angular and Browserify and it is -built using Grunt and Yeoman. +fork this repository and use it to build the same single page application (SPA) +that Stormpath provides by default, and you can make any changes that you +require for your custom version. -If you want to build your own ID Site and are comfortable with Angular, you should -use this repository. - -If you are not using Angular, you can build your own ID Site from scratch -but you will need to use [Stormpath.js][] in order to communicate with our API -from your custom ID Site application. +This default application is built with Angular and has default views and styling. +If you need to make significant changes that don't fit within this application, +you may want to use [Stormpath.js][] instead. That is a smaller library that +gives you the necessary Stormpath APIs to do user management, but does not come +with pre-built views or styling. ## Browser Support -ID Site will work in the following web browser environments: +This ID Site application will work in the following web browser environments: * Chrome (all versions) * Internet Explorer 10+ @@ -34,64 +33,88 @@ It is assumed that you have the following tools installed on your computer * [Bower][] * [Grunt][] * [Node.JS][] -* [Localtunnel.me][] -You should clone this repository and these tasks within the repository: +**Note**: At this time, only node version `4.x` is supported. + +You should clone this repository and then run this within the repository: ```sh npm install bower install ``` -## Setup an HTTPS proxy +## Getting started with `ez_dev` + +Within this repository, there's a script called `ez_dev.sh`. This will setup a complete development environment for you +to be able to work on your ID Site application. + +Before we get into running the script, let's take a step back to see what `ez_dev` sets up. If you want to jump right +in, go to the [running ez_dev](#running-ez_dev) section. + +A typical flow for using ID Site is the following: + +1. Your make a request of the `/login` endpoint of your application in the browser. +2. Your application redirects the browser to Stormapth (api.stormpath.com/sso). +3. Stormpath redirects the browser to your ID Site, as configured in the Stormpath Admin Console. +4. The ID Site application loads in your browser and presents the login form. +5. After login or registration, your browser is directed back to the server from step 1. -Because ID Site only works with HTTPS, you will need to setup a local tunnel -which will serve your your local ID Site from a secure connection. With the -local tunnel tool you must do this: +When customizing ID Site on your local machine, you need: -> lt --port 9000 +* A web server to handle steps 1 and 5 +* A web server to serve the assets at step 4, that would usually be handled by Stormpath. +* SSL encryption for step 3, as required by Stormpath. -It will fetch a URL and tell you something like this: +The `ez_dev` script sets up the necessary architecture needed. The components are: -> your url is: https://wqdkeiseuj.localtunnel.me +1. `fakesp` - A web server that will handle steps 1 and 5. +2. `localtunnel.me` - A free service that sets up an HTTPS proxy from the public internet to a locally running server. +3. `grunt serve` - A locally running instance of ID Site. -You must take that URL and configure your ID Site accordingly. Please login -to the [Stormpath Admin Console][] and set these options on your ID Site -Configuration: +Once this is all running, you browser will automatically open up to: `http://localhost:8001` and you will be able to see the +updated ID Site content you are working on. Any saved changes to the ID Site content are immediately reflected in your browser +when you go to an ID Site view (such as `/login`). -| Configuration Option | Should be set to | -|----------------------------------------|-------------------------------------------------------------------------------------| -| **Domain Name** | your local tunnel URL | -| **Authorized Javascript Origin URLs** | your local tunnel URL should be in this list | -| **Authorized Redirect URLs** | the endpoint on your server application which will receive the user after ID site (read below) | +Here's a visual representation of what is setup and the flow of the requests. -## Your Service Provider (required) +![tunnel architecture][tunnel_image] -The application (typically, your server) that sends the user to ID Site is known -as the Service Provider (SP). You send the user to ID Site by constructing a -redirect URL with one of our SDKs. For example, [createIdSiteUrl()][] in our -Node.js SDK. +### Running `ez_dev` -After the user authenticates at ID Site, the user is redirected back to your -application. Your application must have a callback URL which receives the user -and validates the `jwtResponse` parameter in the URL (our SDK does this work -for you). +`ez_dev` needs to know the following: -If you haven't built your service provider we have a simple service provider -application which you can use for testing purposes, see: [Fake SP][] +1. Your Stormpath API Key ID +2. Your Stormpath API Key secret +3. Your Stormpath Application HREF +The script will look for some common environment variables and file locations in this order: -## Startup +1. If `STORMPATH_API_KEY_FILE` is set, it will get the API Key ID and API Key Secret from that file +2. If `~/.stormpath/apiKey.properties` exists, it will get the API Key ID and API Key Secret from that file +3. If `STORMPATH_APPLICATION_HREF` is set, it will use that value for the Stormpath Application to connect to -Once you have setup the environment (the steps above) you are ready to start -the development tasks. Run the following command to start the server: +If neither 1. or 2. above is met, you will be asked to provide the API Key ID and the API Key Secret to the script -> grunt serve +If 3. above is not met, you will be asked to provide the Application HREF. *Note*: You can leave this value blank if +you only have the default application (`My Application`) defined in your Stormpath tenant from when it was first setup. +If you have any other Applications defined, then you must specify the Application HREF. -This will open the application your browser. Because the application does not -have a JWT request, you will see the JWT error. At this point you should use -your service provider to redirect the user to your ID Site. +Here are a few run scenarios: + +``` +./ez_dev.sh # may be asked to provide additional information +``` + +``` +# explicit settings - you will not be asked for any additional information +STORMPATH_API_KEY_FILE=~/.stormpath/apiKey.mytenant.properties \ +STORMPATH_APPLICATION_HREF=https://api.stormpath.com/v1/applications/stormpathidentifier123456 \ +./ez_dev.sh +``` +Note: The `ez_dev` script alters the ID Site settings in your Stormpath Admin Console. When you are done working on +ID Site, it is recommended that you go back to your Admin Console and revert the `Domain Name`, +`Authorized Javascript Origin URLs`, and `Authorized Redirect URLs` settings. ## Development Process - Stormpath Tenants @@ -179,7 +202,7 @@ License](http://www.apache.org/licenses/LICENSE-2.0). [Fake SP]: https://github.com/robertjd/fakesp [Grunt]: http://gruntjs.com [ID Site Repository]: https://github.com/stormpath/idsite -[Localtunnel.me]: http://localtunnel.me/ [Node.JS]: http://nodejs.org [Stormpath Admin Console]: https://api.stormpath.com [Stormpath.js]: https://github.com/stormpath/stormpath.js +[tunnel_image]: https://github.com/stormpath/idsite-src/blob/media/docs_images/idsite_tunnel_dev.png diff --git a/ez_dev.sh b/ez_dev.sh new file mode 100755 index 0000000..5f58a9f --- /dev/null +++ b/ez_dev.sh @@ -0,0 +1,165 @@ +#! /bin/bash + +function get_property +{ + FILE=$1 + PROPERTY=$2 + sed '/^\#/d' $FILE | grep $PROPERTY | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' +} + +function wait_on_service +{ + URL=$1 + for i in {1..10}; do + STATUS=`curl -s -I $URL | head -n1 | cut -d$' ' -f2` + if [ "$STATUS" == "" ]; then + STATUS=0 + fi + if [ $STATUS == "200" ]; then + break + fi + sleep 1 + done + if [ $STATUS != "200" ]; then + echo "Unable to connect to $URL." + exit 1 + fi +} + + + +echo "Setting up..." +echo + +hash npm 2>/dev/null || { echo >&2 "npm is required, but it's not installed. Install via: https://github.com/tj/n"; exit 1; } +hash bower 2>/dev/null || { echo >&2 "bower is required, but it's not installed. Install via: npm install -g bower"; exit 1; } +hash grunt 2>/dev/null || { echo >&2 "grunt is required, but it's not installed. Install via: npm install -g grunt-cli"; exit 1; } +hash curl 2> /dev/null || { echo >&2 "curl is required, but it's not installed. Install via: brew install curl (on mac)"; exit 1; } + +if [ -n "${STORMPATH_API_KEY_FILE}" ]; then + STORMPATH_CLIENT_APIKEY_ID=`get_property ${STORMPATH_API_KEY_FILE} "apiKey.id"` + STORMPATH_CLIENT_APIKEY_SECRET=`get_property ${STORMPATH_API_KEY_FILE} "apiKey.secret"` +elif [ -a ~/.stormpath/apiKey.properties ]; then + STORMPATH_CLIENT_APIKEY_ID=`get_property ~/.stormpath/apiKey.properties "apiKey.id"` + STORMPATH_CLIENT_APIKEY_SECRET=`get_property ~/.stormpath/apiKey.properties "apiKey.secret"` +fi + +[ -z "${STORMPATH_CLIENT_APIKEY_ID}" ] && read -e -p "Enter your Stormpath API Key ID and press [ENTER]: " STORMPATH_CLIENT_APIKEY_ID +[ -z "${STORMPATH_CLIENT_APIKEY_ID}" ] && echo "Must specify a Stormpath API Key ID" && exit 1 + +[ -z "${STORMPATH_CLIENT_APIKEY_SECRET}" ] && read -e -p "Enter your Stormpath API Key Secret and press [ENTER]: " STORMPATH_CLIENT_APIKEY_SECRET +[ -z "${STORMPATH_CLIENT_APIKEY_SECRET}" ] && echo "Must specify a Stormpath API Key Secret" && exit 1 + +[ -z "${STORMPATH_APPLICATION_HREF}" ] && read -e -p "Enter your Stormpath Application HREF and press [ENTER] (default: default Stormpath Application): " STORMPATH_APPLICATION_HREF + +[ -z "${DOMAIN}" ] && DOMAIN=localhost + +export STORMPATH_CLIENT_APIKEY_ID STORMPATH_CLIENT_APIKEY_SECRET STORMPATH_APPLICATION_HREF DOMAIN + +echo "Executing: npm install..." +npm install + +if [ $? -eq 0 ] +then + echo "Successfully ran: npm install" +else + echo "npm install failed" +fi + +echo "Executing: bower install..." +bower install + +if [ $? -eq 0 ] +then + echo "Successfully ran: bower install" +else + echo "bower install failed" +fi + +echo "Setting up ngrok..." +cd ngrok +npm install + +if [ $? -eq 0 ] +then + echo "Successfully setup ngrok" +else + echo "Failed to setup ngrok" +fi + +cd .. + +echo "Setting up fakesp..." +cd fakesp +npm install + +if [ $? -eq 0 ] +then + echo "Successfully setup fakesp" +else + echo "Failed to setup fakesp" +fi + +cd .. +echo + +echo "Running fakesp..." +cd fakesp +EXPR="node server.js > ../fakesp.log 2>&1 &" +eval $EXPR +FAKESP_PID=$! +cd .. + +echo "Waiting for fakesep to be available..." +wait_on_service localhost:8001 + +echo "Running grunt serve..." +EXPR="grunt serve > grunt_serve.log 2>&1 &" +eval $EXPR +GRUNT_SERVE_PID=$! + +echo "Waiting for grunt server to be available..." +wait_on_service localhost:9000 + +echo "Running ngrok..." +cd ngrok +EXPR="node ngrok.js > ../ngrok.log 2>&1 &" +eval $EXPR +NGROK_PID=$! +cd .. + +echo "Waiting for ngrok to be available..." +URL="" +for i in {1..10}; do + URL=`head -n1 ngrok.log` + if [[ "$URL" == *"ngrok.io"* ]]; then + break + fi + sleep 1 +done +if [ "$URL" == "" ]; then + echo "Unable to connect with ngrok." + exit 1 +fi +wait_on_service $URL + +echo +echo "fakesp PID: $FAKESP_PID, ngrok PID: $NGROK_PID, grunt PID: $GRUNT_SERVE_PID" +echo + +echo $FAKESP_PID > kill_ez_dev.pids +echo $NGROK_PID >> kill_ez_dev.pids +echo $GRUNT_SERVE_PID >> kill_ez_dev.pids + +echo "Tail the logs for more information:" +echo -e "\tfakesp.log" +echo -e "\tngrok.log" +echo -e "\tgrunt_serve.log" +echo + +echo "run: ./kill_ez_dev.sh to kill ez dev" +echo + +echo "Launching browser..." +sleep 1 +open http://localhost:8001 diff --git a/fakesp/README.md b/fakesp/README.md new file mode 100644 index 0000000..82a3448 --- /dev/null +++ b/fakesp/README.md @@ -0,0 +1,59 @@ +### Fake service provider + +Use this to imitate a service-provider initiated login flow for the +Stormpath ID Site Feature. The repo contains a simple HTTP server +that serves a webapp which will redirect you to ID site for authentication. +When you return from ID site, a local cookie-based session will be created +for you. This is different from the SSO session which ID site retains +for you. + +### Installation + +`git clone` this repo, then `cd` into the folder + +`npm install` inside the folder + +### Configuration - Your Dev Machine + +Point `stormpath.localhost` to `127.0.0.1` by putting an entry into `/etc/hosts` + +Export the configuration for a Stormpath Application, with API keys, to your environment: + + export STORMPATH_CLIENT_APIKEY_ID=XXX + export STORMPATH_CLIENT_APIKEY_SECRET=XXX + export STORMPATH_APPLICATION_HREF=https://api.stormpath.com/v1/applications/XXX + +### Configuration - Your Stormpath Tenant + +Login to your Stormpath Tenant and add the following URLs to the list of +"Authorized Redirect URLs" in your ID Site configuration: + + http://stormpath.localhost:8001/idSiteCallback + +### Start the Server + +You can run the server with default options like so: + +``` +node server.js +``` + +Or with options: + +``` +ID_SITE_PATH= \ +PORT=8001 \ +DOMAIN=stormpath.localhost \ +CB_URI=http://stormpath.localhost:8001/idSiteCallback \ +node server.js +``` + +If the server starts sucessfully, you will see this message in your console: + +``` +Starting server on port 8001 +Server running, open this URL in your browser: +http://stormpath.localhost:8001 +``` + +You can now use the application by navigating to http://stormpath.localhost:8001 diff --git a/fakesp/package.json b/fakesp/package.json new file mode 100644 index 0000000..f851751 --- /dev/null +++ b/fakesp/package.json @@ -0,0 +1,22 @@ +{ + "name": "fakesp", + "version": "0.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "client-sessions": "^0.7.0", + "express": "^4.9.6", + "jade": "^1.7.0", + "njwt": "^0.2.2", + "node-uuid": "^1.4.1", + "open": "0.0.5", + "request": "^2.70.0", + "stormpath": "^0.15.4" + } +} diff --git a/fakesp/server.js b/fakesp/server.js new file mode 100644 index 0000000..2dd77c7 --- /dev/null +++ b/fakesp/server.js @@ -0,0 +1,192 @@ +var express = require('express'); +var nJwt = require('njwt'); +var sessions = require('client-sessions'); +var stormpath = require('stormpath'); +var request = require('request'); +var url = require('url'); + +var IS_PRODUCTION = process.env.NODE_ENV==='production'; +var PORT = process.env.PORT || 8001; +var DOMAIN = process.env.DOMAIN || 'localhost'; +var ID_SITE_PATH = process.env.ID_SITE_PATH || ''; +var CB_URI = process.env.CB_URI || ('http://' + DOMAIN + ':' + PORT + '/idSiteCallback' ); + +var app = express(); +var application; +var client = new stormpath.Client(); + +app.set('views', './views'); +app.set('view engine', 'jade'); + + +var spCookieInterface = sessions({ + cookieName: 'sp', // cookie name dictates the key name added to the request object + secret: 'will be set after client initialization', // should be a large unguessable string + duration: 24 * 60 * 60 * 1000, // how long the session will stay valid in ms + activeDuration: 1000 * 60 * 5 // if expiresIn < activeDuration, the session will be extended by activeDuration milliseconds +}); + +var lastJwtCookieInterface = sessions({ + cookieName: 'lastJwt', // cookie name dictates the key name added to the request object + secret: 'will be set after client initialization', // should be a large unguessable string + duration: 24 * 60 * 60 * 1000, // how long the session will stay valid in ms + activeDuration: 1000 * 60 * 5 // if expiresIn < activeDuration, the session will be extended by activeDuration milliseconds +}); + +var idSiteBaseUrlCookieInterface = sessions({ + cookieName: 'idSiteBaseUrl', // cookie name dictates the key name added to the request object + secret: 'will be set after client initialization', // should be a large unguessable string + duration: 24 * 60 * 60 * 1000, // how long the session will stay valid in ms + activeDuration: 1000 * 60 * 5 // if expiresIn < activeDuration, the session will be extended by activeDuration milliseconds +}); + +app.use(lastJwtCookieInterface); +app.use(spCookieInterface); +app.use(idSiteBaseUrlCookieInterface); + +app.get('/', function(req, res){ + if(req.sp && req.sp.accountHref){ + client.getAccount(req.sp.accountHref,function(err,account){ + if(err){ + res.render('error',{ + errorText: String(err) + }); + }else{ + res.render('index',{ + lastJwt: req.lastJwt.value ? JSON.stringify(req.lastJwt.value,null,2) : null, + account: account, + accountJson: JSON.stringify(account,null,2), + cb_uri: CB_URI, + idSiteBaseUrl: req.idSiteBaseUrl.value + }); + } + }); + }else{ + + res.render('index',{ + lastJwt: req.lastJwt.value ? JSON.stringify(req.lastJwt.value,null,2) : null, + account: null, + cb_uri: CB_URI, + idSiteBaseUrl: req.idSiteBaseUrl.value + }); + + } +}); + +app.get('/idSiteCallback',function(req,res){ + if(req.query.jwtResponse){ + application.handleIdSiteCallback(req.url,function(err,idSiteResult){ + if(err){ + res.render('error',{ + errorText: JSON.stringify(err) + }); + }else{ + if(idSiteResult.status !== 'LOGOUT'){ + req.sp.accountHref = idSiteResult.account.href; + } + req.lastJwt.value = nJwt.verify(req.query.jwtResponse,client.config.client.apiKey.secret); + res.redirect('/'); + } + }); + } +}); + + +app.get('/login', function(req, res){ + + var options = { + callbackUri: req.query.cb_uri || CB_URI, + path: ID_SITE_PATH + }; + + if(req.query.sof){ + options.showOrganizationField = Boolean(parseInt(req.query.sof,10)); + } + + if(req.query.onk){ + options.organizationNameKey = req.query.onk; + } + + if(req.query.usd){ + options.useSubDomain = true; + } + + if(req.query.state){ + options.state = req.query.state; + } + + if(req.query.path){ + options.path = req.query.path; + } + var ssoRequestUrl = application.createIdSiteUrl(options); + + if(req.query.idSiteBaseUrl) { + var parsedIdSiteBaseUrl = url.parse(req.query.idSiteBaseUrl); + var idSiteBaseUrl = parsedIdSiteBaseUrl.protocol + '//' + parsedIdSiteBaseUrl.host; + req.idSiteBaseUrl.value = idSiteBaseUrl; + + request({ + method: 'GET', + url: ssoRequestUrl, + followRedirect: false + }, function (err, response, body) { + var idSiteRedirectUrl = response.headers.location || ''; + if (err) { + res.json(err); + } else if(response.statusCode !== 302) { + res.json(body); + } else if(idSiteRedirectUrl.match(/jwtResponse/)) { + res.redirect(response.location); + } else if(req.query.idSiteBaseUrl) { + var parts = idSiteRedirectUrl.split('/#'); + var newUrl = idSiteBaseUrl + '/#' + parts[1]; + res.setHeader('Location', newUrl); + res.status(302); + res.end(); + } else { + res.redirect(idSiteRedirectUrl); + } + }); + } else { + req.idSiteBaseUrl.value = ''; + res.redirect(ssoRequestUrl); + } + +}); + +app.get('/logout', function(req, res){ + req.sp.destroy(); + res.redirect(application.createIdSiteUrl({ + callbackUri: CB_URI, + logout: true + })); +}); + + + + +function startServer(){ + lastJwtCookieInterface.secret = client.config.apiKey.secret; + spCookieInterface.secret = client.config.apiKey.secret; + console.log('Starting server on port ' + PORT); + app.listen(PORT,function(){ + console.log('Server running, open this URL in your browser:'); + console.log('http://'+DOMAIN+':'+PORT); + }); + +} + +function getApplication(then){ + client.getApplication(client.config.application.href,function(err,a){ + if (err){ + throw err; + } + application = a; + then(); + }); +} + + +client.on('ready',function(){ + getApplication(startServer); +}); diff --git a/fakesp/views/error.jade b/fakesp/views/error.jade new file mode 100644 index 0000000..82b84d3 --- /dev/null +++ b/fakesp/views/error.jade @@ -0,0 +1,8 @@ +html + head + link(rel='stylesheet', type='text/css', href='//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css') + body + pre.alert.alert-danger=errorText + p   + center + a.btn.btn-primary.btn-lg(href="/") Return to home page \ No newline at end of file diff --git a/fakesp/views/index.jade b/fakesp/views/index.jade new file mode 100644 index 0000000..0ca3a78 --- /dev/null +++ b/fakesp/views/index.jade @@ -0,0 +1,45 @@ +html + head + link(rel="stylesheet", type="text/css", href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css") + body + div.container + if !account + p   + p   + include login-form + + + if account + h2 You are loggen in + hr + p + | You have a cookie-based session, tied to this server. You can now do one of the following: + table.table.table-bordered + tr + td + p + | If your SSO cookie is still valid you will be immediately redirected back here. + | If your SSO cookie has expired you will be presented with the ID Site login application + include login-form + + tr + td + p + | This will send you to the ID Site with a logout request. + | You will return to this application and your session will be destroyed + div.panel.panel-default + div.panel-heading Logout Request + div.panel-body + center + a.btn.btn-primary(href='/logout') Logout + .panel.panel-default + .panel-heading + h3.panel-title Account of current session: + .panel-body + pre=accountJson + if lastJwt + div.panel.panel-default + div.panel-heading + h3.panel-title Last seen JWT: + div.panel-body + pre=lastJwt \ No newline at end of file diff --git a/fakesp/views/login-form.jade b/fakesp/views/login-form.jade new file mode 100644 index 0000000..c4f3def --- /dev/null +++ b/fakesp/views/login-form.jade @@ -0,0 +1,67 @@ +script(type="application/javascript"). + function revertIdSiteBaseUrl() { + var idSiteBaseUrlInupt = document.getElementById('idSiteBaseUrl'); + idSiteBaseUrlInupt.value = ''; + } +form.form-horizontal(action="/login",method="get") + div.panel.panel-default + div.panel-heading + h3.panel-title Login Request + div.panel-body + div.form-group + label.control-label.col-xs-4 Show Organization Field + div.col-xs-6.col-sm-3.col-md-2 + div.radio + label + input(type="radio" name="sof" checked value="") + span Undefined + div.radio + label + input(type="radio" name="sof" value="1") + span True + div.radio + label + input(type="radio" name="sof" value="0") + span False + + div.form-group + label.control-label.col-xs-4 Organization Name Key + div.col-xs-6.col-sm-3.col-md-2 + input.form-control(type="text" name="onk") + + div.form-group + label.control-label.col-xs-4 Use Subdomain + div.col-xs-6.col-sm-3.col-md-2 + div.checkbox + label + input(type="checkbox" name="usd") + + div.form-group + label.control-label.col-xs-4 State + div.col-xs-6.col-sm-3.col-md-2 + input.form-control(type="text" name="state") + + div.form-group + label.control-label.col-xs-4 Path + div.col-xs-6.col-sm-3.col-md-2 + input.form-control(type="text" name="path") + + div.form-group + label.control-label.col-xs-4 Callback URI + div.col-xs-6.col-sm-3.col-md-5 + input.form-control(type="text" name="cb_uri" value=cb_uri) + + div.form-group + label.control-label.col-xs-4 Alternate ID Site Base URL + div.col-xs-6.col-sm-3.col-md-5 + div.input-group + input.form-control(type="text" name="idSiteBaseUrl" id="idSiteBaseUrl" value=idSiteBaseUrl) + + div.input-group-addon(style="cursor:pointer;" onclick="revertIdSiteBaseUrl(this)") + i.icon.glyphicon.glyphicon-trash + span.help-block Use for local ID Site development. Note: will not persist SSO cookie. + + div.form-group + label.control-label.col-xs-4 + div.col-xs-6.col-sm-3.col-md-2 + button.btn.btn-primary.form-control(type="submit") Log me in! \ No newline at end of file diff --git a/kill_ez_dev.sh b/kill_ez_dev.sh new file mode 100755 index 0000000..b70017f --- /dev/null +++ b/kill_ez_dev.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +for i in `cat kill_ez_dev.pids`; do kill $i; done diff --git a/localtunnel.js b/ngrok/ngrok.js similarity index 88% rename from localtunnel.js rename to ngrok/ngrok.js index 8700b6f..d15cefd 100644 --- a/localtunnel.js +++ b/ngrok/ngrok.js @@ -1,7 +1,10 @@ -var localtunnel = require('localtunnel'); +var ngrok = require('ngrok'); var stormpath = require('stormpath'); -var callbckUri = 'http://stormpath.localhost:8001/idSiteCallback'; +var DOMAIN = process.env.DOMAIN || 'localhost'; +var PORT = process.env.PORT || 8001; + +var callbckUri = process.env.CB_URI || ('http://' + DOMAIN + ':' + PORT + '/idSiteCallback' ); var client = new stormpath.Client(); var doCleanup = false; var previousDomainName = null; @@ -84,14 +87,12 @@ function cleanup(cb){ } } -console.log(process.env.PORT); - -var tunnel = localtunnel(process.env.PORT || 9000, function(err, tunnel) { +ngrok.connect(process.env.PORT || 9000, function(err, url) { if (err) { console.error(err); return process.exit(1); } - host = tunnel.url; + host = url; console.log(host); prepeareIdSiteModel(client,host,callbckUri,function(err){ if (err) { @@ -104,12 +105,12 @@ var tunnel = localtunnel(process.env.PORT || 9000, function(err, tunnel) { }); -tunnel.on('error', function (err) { +ngrok.on('error', function (err) { console.error(err); cleanup(); }); -tunnel.on('close', cleanup); +ngrok.on('disconnect', cleanup); process.on('SIGTERM', function() { console.log('\nCaught termination signal'); @@ -123,4 +124,4 @@ process.on('SIGINT', function() { cleanup(function (){ process.exit(); }); -}); \ No newline at end of file +}); diff --git a/ngrok/package.json b/ngrok/package.json new file mode 100644 index 0000000..ef0d30a --- /dev/null +++ b/ngrok/package.json @@ -0,0 +1,13 @@ +{ + "name": "stormpathidp", + "version": "0.5.0", + "devDependencies": { + "ngrok": "^2.2.2", + "stormpath": "^0.18.2" + }, + "engines": { + "node": ">=0.10.0" + }, + "license": "Apache-2.0", + "homepage": "https://github.com/stormpath/idsite-src" +} diff --git a/package.json b/package.json index 381517e..17ed218 100644 --- a/package.json +++ b/package.json @@ -44,12 +44,11 @@ "karma-ng-html2js-preprocessor": "^0.1.0", "karma-ng-scenario": "^0.1.0", "load-grunt-tasks": "~0.4.0", - "localtunnel": "^1.7.0", "mocha": "^2.2.5", + "ngrok": "^2.2.2", "protractor": "^0.22.0", "q": "^1.4.1", "request": "^2.58.0", - "stormpath": "^0.18.2", "time-grunt": "~0.2.1", "untildify": "^2.0.0" },