1
0
Fork 0
mirror of https://github.com/openstf/stf synced 2025-10-06 12:00:08 +02:00

Add UI to LDAP login.

This commit is contained in:
Simo Kinnunen 2014-01-31 21:39:07 +09:00
parent 01339b089e
commit 9119dcca63
15 changed files with 291 additions and 14 deletions

View file

@ -194,6 +194,9 @@ program
, 'session SSID (or $SSID)' , 'session SSID (or $SSID)'
, String , String
, process.env.SSID || 'ssid') , process.env.SSID || 'ssid')
.option('-a, --app-url <url>'
, 'URL to app'
, String)
.option('-u, --ldap-url <url>' .option('-u, --ldap-url <url>'
, 'LDAP server URL (or $LDAP_URL)' , 'LDAP server URL (or $LDAP_URL)'
, String , String
@ -202,6 +205,10 @@ program
, 'LDAP timeout (or $LDAP_TIMEOUT)' , 'LDAP timeout (or $LDAP_TIMEOUT)'
, Number , Number
, process.env.LDAP_TIMEOUT || 1000) , process.env.LDAP_TIMEOUT || 1000)
.option('--ldap-bind-enable <dn>'
, 'LDAP bind DN (or $LDAP_BIND_DN)'
, String
, process.env.LDAP_BIND_DN)
.option('--ldap-bind-dn <dn>' .option('--ldap-bind-dn <dn>'
, 'LDAP bind DN (or $LDAP_BIND_DN)' , 'LDAP bind DN (or $LDAP_BIND_DN)'
, String , String
@ -221,12 +228,24 @@ program
.option('--ldap-search-class <class>' .option('--ldap-search-class <class>'
, 'LDAP search objectClass (or $LDAP_SEARCH_CLASS)' , 'LDAP search objectClass (or $LDAP_SEARCH_CLASS)'
, String , String
, process.env.LDAP_SEARCH_CLASS || 'user') , process.env.LDAP_SEARCH_CLASS || 'top')
.option('--ldap-search-field <name>'
, 'LDAP search field (or $LDAP_SEARCH_FIELD)'
, String
, process.env.LDAP_SEARCH_FIELD)
.action(function(options) { .action(function(options) {
if (!options.secret) {
this.missingArgument('--secret')
}
if (!options.appUrl) {
this.missingArgument('--app-url')
}
require('./roles/auth/ldap')({ require('./roles/auth/ldap')({
port: options.port port: options.port
, secret: options.secret , secret: options.secret
, ssid: options.ssid , ssid: options.ssid
, appUrl: options.appUrl
, ldap: { , ldap: {
url: options.ldapUrl url: options.ldapUrl
, timeout: options.ldapTimeout , timeout: options.ldapTimeout
@ -238,7 +257,7 @@ program
dn: options.ldapSearchDn dn: options.ldapSearchDn
, scope: options.ldapSearchScope , scope: options.ldapSearchScope
, objectClass: options.ldapSearchClass , objectClass: options.ldapSearchClass
, loginField: options.ldapSearchLoginField , field: options.ldapSearchField
} }
} }
}) })

View file

@ -7,12 +7,18 @@ var logger = require('../../util/logger')
var requtil = require('../../util/requtil') var requtil = require('../../util/requtil')
var ldaputil = require('../../util/ldaputil') var ldaputil = require('../../util/ldaputil')
var jwtutil = require('../../util/jwtutil') var jwtutil = require('../../util/jwtutil')
var pathutil = require('../../util/pathutil')
var urlutil = require('../../util/urlutil') var urlutil = require('../../util/urlutil')
module.exports = function(options) { module.exports = function(options) {
var log = logger.createLogger('auth-ldap') var log = logger.createLogger('auth-ldap')
, app = express() , app = express()
app.set('view engine', 'jade')
app.set('views', pathutil.resource('auth-ldap/views'))
app.set('strict routing', true)
app.set('case sensitive routing', true)
app.use(express.cookieParser()) app.use(express.cookieParser())
app.use(express.cookieSession({ app.use(express.cookieSession({
secret: options.secret secret: options.secret
@ -20,13 +26,34 @@ module.exports = function(options) {
})) }))
app.use(express.json()) app.use(express.json())
app.use(express.urlencoded()) app.use(express.urlencoded())
app.use(express.csrf())
app.use(validator()) app.use(validator())
app.use('/static/lib', express.static(pathutil.resource('lib')))
app.use('/static', express.static(pathutil.resource('auth-ldap')))
app.get('/auth', function(req, res) { app.use(function(req, res, next) {
res.locals.csrf = req.csrfToken() res.cookie('XSRF-TOKEN', req.csrfToken());
next()
}) })
app.post('/auth', function(req, res) { app.get('/partials/:name', function(req, res) {
var whitelist = {
'signin': true
}
if (whitelist[req.params.name]) {
res.render('partials/' + req.params.name)
}
else {
res.send(404)
}
})
app.get('/', function(req, res) {
res.render('index')
})
app.post('/api/v1/auth', function(req, res) {
var log = logger.createLogger('auth-ldap') var log = logger.createLogger('auth-ldap')
log.setLocalIdentifier(req.ip) log.setLocalIdentifier(req.ip)
switch (req.accepts(['json'])) { switch (req.accepts(['json'])) {

View file

@ -25,6 +25,7 @@ module.exports.login = function(options, username, password) {
, maxConnections: 1 , maxConnections: 1
}) })
if (options.bind.dn) {
client.bind(options.bind.dn, options.bind.credentials, function(err) { client.bind(options.bind.dn, options.bind.credentials, function(err) {
if (err) { if (err) {
resolver.reject(err) resolver.reject(err)
@ -33,6 +34,10 @@ module.exports.login = function(options, username, password) {
resolver.resolve(client) resolver.resolve(client)
} }
}) })
}
else {
resolver.resolve(client)
}
return resolver.promise return resolver.promise
} }
@ -48,7 +53,7 @@ module.exports.login = function(options, username, password) {
, value: options.search.objectClass , value: options.search.objectClass
}) })
, new ldap.EqualityFilter({ , new ldap.EqualityFilter({
attribute: options.search.loginField attribute: options.search.field
, value: username , value: username
}) })
] ]

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View file

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

11
res/auth-ldap/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,37 @@
define(['./module'], function(mod) {
mod.controller('SignInCtrl', ['$scope', '$http', function($scope, $http) {
$scope.error = null
$scope.submit = function() {
var data = {
username: $scope.signin.username.$modelValue
, password: $scope.signin.password.$modelValue
}
$scope.invalid = false
$http.post('/api/v1/auth', data)
.success(function(response) {
$scope.error = null
location.replace(response.redirect)
})
.error(function(response) {
switch (response.error) {
case 'ValidationError':
$scope.error = {
$invalid: true
}
break
case 'InvalidCredentialsError':
$scope.error = {
$incorrect: true
}
break
default:
$scope.error = {
$server: true
}
break
}
})
}
}])
})

View file

@ -0,0 +1,6 @@
define([
'./SignInCtrl'
]
, function() {
}
)

View file

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

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'
]
})

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: '/'
})
}
])
})

View file

@ -0,0 +1,79 @@
body {
background: #eeeeee;
}
.login2 {
padding: 30px 0 0;
background: #eeeeee;
}
.login2 .login-wrapper {
max-width: 420px;
margin: 0 auto;
text-align: center;
}
.login2 .login-wrapper img {
margin: 40px auto;
}
.login2 .login-wrapper .input-group-addon {
padding: 8px 0;
background: #f4f4f4;
min-width: 48px;
text-align: center;
}
.login2 .login-wrapper .input-group-addon i.falock {
font-size: 18px;
}
.login2 .login-wrapper input.form-control {
height: 48px;
font-size: 15px;
box-shadow: none;
}
.login2 .login-wrapper .checkbox {
margin-bottom: 30px;
}
.login2 .login-wrapper input[type="submit"] {
padding: 10px 0 12px;
margin: 20px 0 30px;
}
.login2 .login-wrapper input[type="submit"]:hover {
background: transparent;
}
.login2 .login-wrapper .social-login {
margin-bottom: 20px;
padding-bottom: 25px;
border-bottom: 1px solid #cccccc;
}
.login2 .login-wrapper .social-login > .btn {
width: 49%;
margin: 0;
}
.login2 .login-wrapper .social-login .facebook {
background-color: #335397;
border-color: #335397;
}
.login2 .login-wrapper .social-login .facebook:hover {
background-color: transparent;
color: #335397;
}
.login2 .login-wrapper .social-login .twitter {
background-color: #00c7f7;
border-color: #00c7f7;
}
.login2 .login-wrapper .social-login .twitter:hover {
background-color: transparent;
color: #00c7f7;
}

View file

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

View file

@ -0,0 +1,28 @@
.login2
.login-wrapper
a(href='./')
img(width='128', height='128', src='/static/images/logo-128.png', title='STF')
form(name='signin', novalidate, ng-submit='submit()')
.alert.alert-danger(ng-show='error')
span(ng-show='error.$invalid') Check errors below
span(ng-show='error.$incorrect') Incorrect login details
span(ng-show='error.$system') System error
.form-group
.input-group
span.input-group-addon
i.fa.fa-envelope
input.form-control(ng-model='username', name='username', required, type='text', placeholder='LDAP Username')
.alert.alert-warning(ng-show='signin.username.$dirty && signin.username.$invalid')
span(ng-show='signin.username.$error.required') Please enter your LDAP username
.form-group
.input-group
span.input-group-addon
i.fa.fa-lock
input.form-control(ng-model='password', name='password', required, type='password', placeholder='Password')
.alert.alert-warning(ng-show='signin.password.$dirty && signin.password.$invalid')
span Please enter your password
input.btn.btn-lg.btn-primary.btn-block(type='submit', value='Log in')

View file

@ -0,0 +1,6 @@
link(href='http://fonts.googleapis.com/css?family=Lato:100,300,400,700', media='all', rel='stylesheet', type='text/css')
link(rel='stylesheet', href='/static/lib/se7en-bootstrap-3/build/stylesheets/bootstrap.min.css')
link(rel='stylesheet', href='/static/lib/se7en-bootstrap-3/build/stylesheets/se7en-font.css')
link(rel='stylesheet', href='/static/lib/se7en-bootstrap-3/build/stylesheets/style.css')
link(rel='stylesheet', href='/static/lib/se7en-bootstrap-3/build/stylesheets/font-awesome.min.css')
link(rel='stylesheet', href='/static/styles/login.css')