1
0
Fork 0
mirror of https://github.com/openstf/stf synced 2025-10-03 17:59:28 +02:00

Make app work with login.

This commit is contained in:
Simo Kinnunen 2014-01-27 15:38:40 +09:00
parent d8ca15d002
commit f2066b35fa
15 changed files with 237 additions and 26 deletions

11
app/app/scripts/app.js Normal file
View file

@ -0,0 +1,11 @@
define([
'angular'
, './controllers/index'
]
, function(ng) {
return ng.module('app', [
'ngRoute'
, 'app.controllers'
])
}
)

11
app/app/scripts/bootstrap.js vendored Normal file
View file

@ -0,0 +1,11 @@
define([
'require'
, 'angular'
, 'angular-route'
, 'app'
, 'routes'
]
, function(require, ng) {
ng.bootstrap(document, ['app'])
}
)

View file

@ -0,0 +1,5 @@
define([
]
, function() {
}
)

View file

@ -0,0 +1,3 @@
define(['angular'], function(ng) {
return ng.module('app.controllers', [])
})

19
app/app/scripts/main.js Normal file
View file

@ -0,0 +1,19 @@
require.config({
paths: {
'angular': '../lib/angular/angular'
, 'angular-route': '../lib/angular-route/angular-route'
}
, shim: {
'angular': {
exports: 'angular'
}
, 'angular-route': {
deps: [
'angular'
]
}
}
, deps: [
'./bootstrap'
]
})

17
app/app/scripts/routes.js Normal file
View file

@ -0,0 +1,17 @@
define(['./app'], function(app) {
return app.config([
'$routeProvider'
, '$locationProvider'
, function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true)
$routeProvider
.when('/', {
templateUrl: 'partials/signin'
, controller: 'SignInCtrl'
})
.otherwise({
redirectTo: '/'
})
}
])
})

7
app/app/views/index.jade Normal file
View file

@ -0,0 +1,7 @@
doctype html
html
head
meta(charset='utf-8')
body(ng-cloak)
div(ng-view)
script(src='/static/lib/requirejs/require.js', data-main='static/scripts/main.js')

View file

@ -6,7 +6,6 @@ define(['./module'], function(mod) {
var data = {
name: $scope.signin.name.$modelValue
, email: $scope.signin.email.$modelValue
, redirect: $scope.signin.redirect.$modelValue
}
$scope.invalid = false
$http.post('/api/v1/auth', data)

View file

@ -15,5 +15,4 @@ form(name='signin', novalidate, ng-submit='submit()')
span(ng-show='signin.email.$error.email') Please enter a valid email address
span(ng-show='signin.email.$error.required') Please enter your email address
div
input(type='text', name='redirect', ng-model='redirect')
button(type='submit') Sign In

View file

@ -1,3 +1,5 @@
var util = require('util')
var program = require('commander')
var pkg = require('../package')
@ -131,7 +133,7 @@ program
.option('-p, --port <port>'
, 'port (or $PORT)'
, Number
, 7100)
, 7120)
.option('-s, --secret <secret>'
, 'secret (or $SECRET)'
, String)
@ -189,6 +191,41 @@ program
program
.command('auth-mock')
.description('start mock auth client')
.option('-p, --port <port>'
, 'port (or $PORT)'
, Number
, 7120)
.option('-s, --secret <secret>'
, 'secret (or $SECRET)'
, String)
.option('-i, --ssid <ssid>'
, 'session SSID (or $SSID)'
, String
, 'ssid')
.option('-a, --app-url <url>'
, 'URL to app'
, String)
.action(function(options) {
var env = process.env
if (!options.secret) {
this.missingArgument('--secret')
}
if (!options.appUrl) {
this.missingArgument('--app-url')
}
require('./roles/auth/mock')({
port: env.PORT || options.port
, secret: options.secret || env.SECRET
, ssid: options.ssid || env.SSID
, appUrl: options.appUrl
})
})
program
.command('app')
.description('start app')
.option('-p, --port <port>'
, 'port (or $PORT)'
, Number
@ -200,12 +237,24 @@ program
, 'session SSID (or $SSID)'
, String
, 'ssid')
.option('-a, --auth-url <url>'
, 'URL to auth client'
, String)
.action(function(options) {
var env = process.env
require('./roles/auth/mock')({
if (!options.secret) {
this.missingArgument('--secret')
}
if (!options.authUrl) {
this.missingArgument('--auth-url')
}
require('./roles/app')({
port: env.PORT || options.port
, secret: options.secret || env.SECRET
, ssid: options.ssid || env.SSID
, authUrl: options.authUrl
})
})
@ -269,6 +318,10 @@ program
, 'auth secret'
, String
, 'kute kittykat')
.option('--app-port <port>'
, 'app port'
, Number
, 7100)
.action(function() {
var log = logger.createLogger('cli')
, options = cliutil.lastArg(arguments)
@ -330,10 +383,22 @@ program
'auth-mock'
, '--port', options.authPort
, '--secret', options.authSecret
, '--app-url', util.format('http://localhost:%d/', options.appPort)
])
.catch(function(err) {
log.error('auth-mock died', err.stack)
})
// app
procutil.fork(__filename, [
'app'
, '--port', options.appPort
, '--secret', options.authSecret
, '--auth-url', util.format('http://localhost:%d/', options.authPort)
])
.catch(function(err) {
log.error('app died', err.stack)
})
})
program.parse(process.argv)

29
lib/middleware/jwt.js Normal file
View file

@ -0,0 +1,29 @@
var jwtutil = require('../util/jwtutil')
var urlutil = require('../util/urlutil')
module.exports = function(options) {
return function(req, res, next) {
if (req.query.jwt) {
// Coming from auth client
var data = jwtutil.decode(req.query.jwt, options.secret)
, redir = urlutil.removeParam(req.url, 'jwt')
if (data) {
// Redirect once to get rid of the token
req.session.jwt = data
res.redirect(redir)
}
else {
// Invalid token, forward to auth client
res.redirect(options.authUrl)
}
}
else if (req.session && req.session.jwt) {
// Continue existing session
next()
}
else {
// No session, forward to auth client
res.redirect(options.authUrl)
}
}
}

43
lib/roles/app.js Normal file
View file

@ -0,0 +1,43 @@
var url = require('url')
var express = require('express')
var validator = require('express-validator')
var logger = require('../util/logger')
var pathutil = require('../util/pathutil')
var jwt = require('../middleware/jwt')
module.exports = function(options) {
var log = logger.createLogger('app')
, app = express()
app.set('view engine', 'jade')
app.set('views', pathutil.resource('app/views'))
app.set('strict routing', true)
app.set('case sensitive routing', true)
app.use(express.cookieParser())
app.use(express.cookieSession({
secret: options.secret
, key: options.ssid
}))
app.use(jwt({
secret: options.secret
, appUrl: options.url
, authUrl: options.authUrl
}))
app.use(express.json())
app.use(express.urlencoded())
app.use(express.csrf())
app.use(validator())
app.use('/static/lib', express.static(pathutil.resource('lib')))
app.use('/static', express.static(pathutil.resource('app')))
app.get('/', function(req, res) {
res.render('index')
})
app.listen(options.port)
log.info('Listening on port %d', options.port)
}

View file

@ -7,6 +7,7 @@ var logger = require('../../util/logger')
var requtil = require('../../util/requtil')
var ldaputil = require('../../util/ldaputil')
var jwtutil = require('../../util/jwtutil')
var urlutil = require('../../util/urlutil')
module.exports = function(options) {
var log = logger.createLogger('auth-ldap')
@ -33,12 +34,6 @@ module.exports = function(options) {
requtil.validate(req, function() {
req.checkBody('username').notEmpty()
req.checkBody('password').notEmpty()
// This is a security risk. Someone might forward the user
// to the login page with their own redirect set, and they'd
// then be able to steal the token. Some kind of a whitelist
// or a fixed redirect URL is needed.
req.checkBody('redirect').isUrl()
})
.then(function() {
return ldaputil.login(
@ -56,14 +51,12 @@ module.exports = function(options) {
}
, secret: options.secret
})
var target = url.parse(req.body.redirect)
target.query = {
jwt: token
}
res.status(200)
.json({
success: true
, redirect: url.format(target)
, redirect: urlutil.addParams(options.appUrl, {
jwt: token
})
})
})
.catch(requtil.ValidationError, function(err) {

View file

@ -7,6 +7,7 @@ var logger = require('../../util/logger')
var requtil = require('../../util/requtil')
var jwtutil = require('../../util/jwtutil')
var pathutil = require('../../util/pathutil')
var urlutil = require('../../util/urlutil')
module.exports = function(options) {
var log = logger.createLogger('auth-mock')
@ -59,12 +60,6 @@ module.exports = function(options) {
requtil.validate(req, function() {
req.checkBody('name').notEmpty()
req.checkBody('email').isEmail()
// This is a security risk. Someone might forward the user
// to the login page with their own redirect set, and they'd
// then be able to steal the token. Some kind of a whitelist
// or a fixed redirect URL is needed.
req.checkBody('redirect').isUrl()
})
.then(function() {
log.info('Authenticated "%s"', req.body.email)
@ -75,14 +70,12 @@ module.exports = function(options) {
}
, secret: options.secret
})
var target = url.parse(req.body.redirect)
target.query = {
jwt: token
}
res.status(200)
.json({
success: true
, redirect: url.format(target)
, redirect: urlutil.addParams(options.appUrl, {
jwt: token
})
})
})
.catch(requtil.ValidationError, function(err) {

17
lib/util/urlutil.js Normal file
View file

@ -0,0 +1,17 @@
var url = require('url')
module.exports.addParams = function(originalUrl, params) {
var parsed = url.parse(originalUrl, true)
parsed.search = null
for (var key in params) {
parsed.query[key] = params[key]
}
return url.format(parsed)
}
module.exports.removeParam = function(originalUrl, param) {
var parsed = url.parse(originalUrl, true)
parsed.search = null
delete parsed.query[param]
return url.format(parsed)
}