mirror of
https://github.com/openstf/stf
synced 2025-10-05 19:42:01 +02:00
Add UI to LDAP login.
This commit is contained in:
parent
01339b089e
commit
9119dcca63
15 changed files with 291 additions and 14 deletions
23
lib/cli.js
23
lib/cli.js
|
@ -194,6 +194,9 @@ program
|
|||
, 'session SSID (or $SSID)'
|
||||
, String
|
||||
, process.env.SSID || 'ssid')
|
||||
.option('-a, --app-url <url>'
|
||||
, 'URL to app'
|
||||
, String)
|
||||
.option('-u, --ldap-url <url>'
|
||||
, 'LDAP server URL (or $LDAP_URL)'
|
||||
, String
|
||||
|
@ -202,6 +205,10 @@ program
|
|||
, 'LDAP timeout (or $LDAP_TIMEOUT)'
|
||||
, Number
|
||||
, 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>'
|
||||
, 'LDAP bind DN (or $LDAP_BIND_DN)'
|
||||
, String
|
||||
|
@ -221,12 +228,24 @@ program
|
|||
.option('--ldap-search-class <class>'
|
||||
, 'LDAP search objectClass (or $LDAP_SEARCH_CLASS)'
|
||||
, 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) {
|
||||
if (!options.secret) {
|
||||
this.missingArgument('--secret')
|
||||
}
|
||||
if (!options.appUrl) {
|
||||
this.missingArgument('--app-url')
|
||||
}
|
||||
|
||||
require('./roles/auth/ldap')({
|
||||
port: options.port
|
||||
, secret: options.secret
|
||||
, ssid: options.ssid
|
||||
, appUrl: options.appUrl
|
||||
, ldap: {
|
||||
url: options.ldapUrl
|
||||
, timeout: options.ldapTimeout
|
||||
|
@ -238,7 +257,7 @@ program
|
|||
dn: options.ldapSearchDn
|
||||
, scope: options.ldapSearchScope
|
||||
, objectClass: options.ldapSearchClass
|
||||
, loginField: options.ldapSearchLoginField
|
||||
, field: options.ldapSearchField
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -7,12 +7,18 @@ var logger = require('../../util/logger')
|
|||
var requtil = require('../../util/requtil')
|
||||
var ldaputil = require('../../util/ldaputil')
|
||||
var jwtutil = require('../../util/jwtutil')
|
||||
var pathutil = require('../../util/pathutil')
|
||||
var urlutil = require('../../util/urlutil')
|
||||
|
||||
module.exports = function(options) {
|
||||
var log = logger.createLogger('auth-ldap')
|
||||
, 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.cookieSession({
|
||||
secret: options.secret
|
||||
|
@ -20,13 +26,34 @@ module.exports = function(options) {
|
|||
}))
|
||||
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('auth-ldap')))
|
||||
|
||||
app.get('/auth', function(req, res) {
|
||||
res.locals.csrf = req.csrfToken()
|
||||
app.use(function(req, res, next) {
|
||||
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')
|
||||
log.setLocalIdentifier(req.ip)
|
||||
switch (req.accepts(['json'])) {
|
||||
|
|
|
@ -25,6 +25,7 @@ module.exports.login = function(options, username, password) {
|
|||
, maxConnections: 1
|
||||
})
|
||||
|
||||
if (options.bind.dn) {
|
||||
client.bind(options.bind.dn, options.bind.credentials, function(err) {
|
||||
if (err) {
|
||||
resolver.reject(err)
|
||||
|
@ -33,6 +34,10 @@ module.exports.login = function(options, username, password) {
|
|||
resolver.resolve(client)
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
resolver.resolve(client)
|
||||
}
|
||||
|
||||
return resolver.promise
|
||||
}
|
||||
|
@ -48,7 +53,7 @@ module.exports.login = function(options, username, password) {
|
|||
, value: options.search.objectClass
|
||||
})
|
||||
, new ldap.EqualityFilter({
|
||||
attribute: options.search.loginField
|
||||
attribute: options.search.field
|
||||
, value: username
|
||||
})
|
||||
]
|
||||
|
|
BIN
res/auth-ldap/images/logo-128.png
Normal file
BIN
res/auth-ldap/images/logo-128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
11
res/auth-ldap/scripts/app.js
Normal file
11
res/auth-ldap/scripts/app.js
Normal 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
11
res/auth-ldap/scripts/bootstrap.js
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
define([
|
||||
'require'
|
||||
, 'angular'
|
||||
, 'angular-route'
|
||||
, 'app'
|
||||
, 'routes'
|
||||
]
|
||||
, function(require, ng) {
|
||||
ng.bootstrap(document, ['app'])
|
||||
}
|
||||
)
|
37
res/auth-ldap/scripts/controllers/SignInCtrl.js
Normal file
37
res/auth-ldap/scripts/controllers/SignInCtrl.js
Normal 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
|
||||
}
|
||||
})
|
||||
}
|
||||
}])
|
||||
})
|
6
res/auth-ldap/scripts/controllers/index.js
Normal file
6
res/auth-ldap/scripts/controllers/index.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
define([
|
||||
'./SignInCtrl'
|
||||
]
|
||||
, function() {
|
||||
}
|
||||
)
|
3
res/auth-ldap/scripts/controllers/module.js
Normal file
3
res/auth-ldap/scripts/controllers/module.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
define(['angular'], function(ng) {
|
||||
return ng.module('app.controllers', [])
|
||||
})
|
19
res/auth-ldap/scripts/main.js
Normal file
19
res/auth-ldap/scripts/main.js
Normal 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
res/auth-ldap/scripts/routes.js
Normal file
17
res/auth-ldap/scripts/routes.js
Normal 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: '/'
|
||||
})
|
||||
}
|
||||
])
|
||||
})
|
79
res/auth-ldap/styles/login.css
Normal file
79
res/auth-ldap/styles/login.css
Normal 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;
|
||||
}
|
9
res/auth-ldap/views/index.jade
Normal file
9
res/auth-ldap/views/index.jade
Normal 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')
|
28
res/auth-ldap/views/partials/signin.jade
Normal file
28
res/auth-ldap/views/partials/signin.jade
Normal 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')
|
6
res/auth-ldap/views/partials/styles.jade
Normal file
6
res/auth-ldap/views/partials/styles.jade
Normal 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')
|
Loading…
Add table
Add a link
Reference in a new issue