Use OAuth login in the webadmin
Currently the webadmin has a fixed built-in client id, which is added on server startup.
This commit is contained in:
+21
-10
@@ -11,24 +11,25 @@ var server = '<%= protocol %>://<%= domain %>';
|
||||
// handle the oauth flow
|
||||
yellowtent.oauth = {};
|
||||
yellowtent.endOAuth = endOAuth;
|
||||
yellowtent.setupButton = setupButton;
|
||||
|
||||
function startOAuth(event) {
|
||||
var button = event.target.parentElement;
|
||||
function startOAuth(button, resultCallback) {
|
||||
var clientId = button.getAttribute('data-clientid');
|
||||
var callback = button.getAttribute('data-callback');
|
||||
|
||||
yellowtent.oauth = {};
|
||||
yellowtent.oauth.button = button;
|
||||
yellowtent.oauth.clientId = clientId;
|
||||
yellowtent.oauth.callback = callback;
|
||||
yellowtent.oauth.callback = resultCallback || window[callback];
|
||||
yellowtent.oauth.redirectURI = button.getAttribute('data-redirect-uri') || '';
|
||||
|
||||
console.debug('Staring OAuth for client ' + clientId + ' and callback ' + callback);
|
||||
console.log('Staring OAuth for client ' + clientId + ' and callback ' + callback + ' with redirectURI ' + yellowtent.oauth.redirectURI);
|
||||
|
||||
var width = 400;
|
||||
var height = 600;
|
||||
var left = screen.width / 2.0 - width / 2.0;
|
||||
var top = screen.height / 2.0 - height / 2.0;
|
||||
var oauthURI = server + '/api/v1/oauth/dialog/authorize?response_type=code&client_id=' + clientId + '&redirect_uri=' + server + '/oauth2/oauth_callback.html';
|
||||
var oauthURI = server + '/api/v1/oauth/dialog/authorize?response_type=code&client_id=' + clientId + '&redirect_uri=' + server + yellowtent.oauth.redirectURI;
|
||||
|
||||
window.open(oauthURI, 'Yellowtent', 'width=400, height=600, left=' + left + ', top=' + top);
|
||||
}
|
||||
@@ -43,25 +44,35 @@ function endOAuth(result) {
|
||||
return;
|
||||
}
|
||||
|
||||
yellowtent.oauth.button.style.display = 'none';
|
||||
window[yellowtent.oauth.callback].apply(null, [result.authCode]);
|
||||
yellowtent.oauth.callback.apply(null, [result.authCode]);
|
||||
}
|
||||
|
||||
function setupButton(button, resultCallback) {
|
||||
button.innerHTML = '<input class="btn btn-green btn-block" type="button" value="Sign in with Yellowtent"/>';
|
||||
button.onclick = function () {
|
||||
startOAuth(button, resultCallback);
|
||||
};
|
||||
}
|
||||
|
||||
window.addEventListener('load', function () {
|
||||
console.debug('Yellowtent init');
|
||||
console.log('Yellowtent init');
|
||||
|
||||
function clickEventHandler(event) {
|
||||
startOAuth(event.target.parentElement);
|
||||
}
|
||||
|
||||
var signIns = window.document.getElementsByClassName('yellowtent-signin');
|
||||
for (var i = 0; i < signIns.length; ++i) {
|
||||
var button = signIns[0];
|
||||
|
||||
button.innerHTML = '<input class="btn btn-green btn-block" type="button" value="Sign in with Yellowtent"/>';
|
||||
button.onclick = startOAuth;
|
||||
button.onclick = clickEventHandler;
|
||||
}
|
||||
|
||||
}, false );
|
||||
|
||||
window.addEventListener('message', function (event) {
|
||||
console.debug('Yellowtent message received.', event.data);
|
||||
console.log('Yellowtent message received.', event.data);
|
||||
|
||||
if (event.origin !== server) {
|
||||
console.log('Ignore message from unknown source.');
|
||||
|
||||
+2
-2
@@ -193,8 +193,8 @@ Server.prototype._initialize = function (callback) {
|
||||
that.app.post('/api/v1/createadmin', routes.user.createAdmin);
|
||||
|
||||
// routes controlled by app.router
|
||||
that.app.post('/api/v1/token', basic, routes.user.createToken); // TODO remove that route
|
||||
that.app.get('/api/v1/user/token', basic, routes.user.createToken);
|
||||
that.app.post('/api/v1/token', both, routes.user.createToken); // TODO remove that route
|
||||
that.app.get('/api/v1/user/token', both, routes.user.createToken);
|
||||
that.app.get('/api/v1/logout', bearer, routes.user.logout); // TODO remove that route
|
||||
that.app.get('/api/v1/user/logout', bearer, routes.user.logout);
|
||||
that.app.post('/api/v1/user/create', bearer, that._requireAdmin.bind(that), routes.user.create);
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
<script src="3rdparty/js/acute.select.js"></script>
|
||||
<link href="3rdparty/css/acute.select.css" rel="stylesheet" media="screen"/>
|
||||
|
||||
<!-- yellowtent -->
|
||||
<script src="/api/v1/oauth/yellowtent.js"></script>
|
||||
|
||||
<!-- application scripts -->
|
||||
<script src="js/services/client.js"></script>
|
||||
|
||||
@@ -3,48 +3,23 @@
|
||||
function LoginController ($scope, Client) {
|
||||
console.debug('LoginController');
|
||||
|
||||
$scope.username = '';
|
||||
$scope.password = '';
|
||||
$scope.remember = true;
|
||||
$scope.disabled = false;
|
||||
$scope.error = {};
|
||||
// manually tell yellowtent to manage the signInButton
|
||||
window.yellowtent.setupButton(document.getElementById('signInButton'), function (authCode) {
|
||||
if (!authCode) {
|
||||
console.error('User did not finish the OAuth flow.');
|
||||
return;
|
||||
}
|
||||
|
||||
// basically perform passive auth
|
||||
if (Client.getToken()) {
|
||||
Client.tokenLogin(Client.getToken(), function (error, token) {
|
||||
console.debug('Got authCode as result of OAuth flow.', authCode);
|
||||
|
||||
Client.exchangeCodeForToken(authCode, function (error, accessToken) {
|
||||
if (error) {
|
||||
console.error('Unable to login using previous token.', error);
|
||||
console.error('Unable to exchange code for an access token.', error);
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Successfully logged in. New token', token);
|
||||
localStorage.token = accessToken;
|
||||
window.location.href = '#/volumelist';
|
||||
});
|
||||
}
|
||||
|
||||
$scope.submit = function () {
|
||||
console.debug('Try to login with user', $scope.username);
|
||||
|
||||
$scope.error.username = null;
|
||||
$scope.disabled = true;
|
||||
|
||||
Client.login($scope.username, $scope.password, function (error, token) {
|
||||
if (error) {
|
||||
console.error('Unable to login', error);
|
||||
if (error.statusCode === 401) {
|
||||
$scope.error.username = 'Invalid credentials';
|
||||
$scope.disabled = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Successfully logged in got token', token);
|
||||
|
||||
if ($scope.remember) {
|
||||
localStorage.token = token;
|
||||
}
|
||||
|
||||
window.location.href = '#/volumelist';
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,16 +21,45 @@ var MainController = function ($scope, $route, Client) {
|
||||
|
||||
$scope.logout = function () {
|
||||
// TODO actually perform logout on the server
|
||||
localStorage.removeItem('token');
|
||||
Client.logout();
|
||||
window.location.href = '#/';
|
||||
window.location.href = '#/login';
|
||||
};
|
||||
|
||||
Client.tokenLogin(localStorage.token, function (error, result) {
|
||||
Client.setClientCredentials('cid-webadmin', 'unused');
|
||||
Client.isServerFirstTime(function (error, isFirstTime) {
|
||||
if (error) {
|
||||
window.location.href = '#/';
|
||||
console.error('Unable to connect.', error);
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.showSideBar = !!Client._userInfo;
|
||||
console.debug('Successfully connect to server. Server first time', isFirstTime);
|
||||
|
||||
if (isFirstTime) {
|
||||
window.location.href = '#/usercreate?admin=1';
|
||||
return;
|
||||
}
|
||||
|
||||
// Server already initializied, try to perform login based on token
|
||||
if (localStorage.token) {
|
||||
Client.login(localStorage.token, function (error, token) {
|
||||
if (error) {
|
||||
console.error('Unable to login', error);
|
||||
window.location.href = '#/login';
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Successfully logged in got token', token);
|
||||
|
||||
// update token
|
||||
localStorage.token = token;
|
||||
$scope.showSideBar = !!Client._userInfo;
|
||||
window.location.href = '#/volumelist';
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// No token plain login
|
||||
window.location.href = '#/login';
|
||||
});
|
||||
};
|
||||
|
||||
@@ -5,13 +5,6 @@ var SettingsController = function ($scope, Client) {
|
||||
|
||||
$scope.user = Client.getUserInfo();
|
||||
|
||||
$scope.logout = function () {
|
||||
// TODO actually perform logout on the server
|
||||
localStorage.removeItem('token');
|
||||
Client.setToken(null);
|
||||
window.location.href = '#/';
|
||||
};
|
||||
|
||||
$scope.changePassword = function () {
|
||||
window.location.href = '#/userpassword';
|
||||
};
|
||||
|
||||
@@ -7,39 +7,4 @@ var SplashController = function ($scope, Client, Spinner) {
|
||||
spinner.el.style.left = '50%';
|
||||
spinner.el.style.top = '50%';
|
||||
document.getElementById('spinner-container').appendChild(spinner.el);
|
||||
|
||||
Client.isServerFirstTime(function (error, isFirstTime) {
|
||||
if (error) {
|
||||
console.error('Unable to connect.', error);
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Successfully connect to server. Server first time', isFirstTime);
|
||||
|
||||
if (isFirstTime) {
|
||||
window.location.href = '#/usercreate?admin=1';
|
||||
return;
|
||||
}
|
||||
|
||||
// Server already initializied, try to perform login based on token
|
||||
if (localStorage.token) {
|
||||
Client.tokenLogin(localStorage.token, function (error, token) {
|
||||
if (error) {
|
||||
console.error('Unable to login', error);
|
||||
window.location.href = '#/login';
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Successfully logged in got token', token);
|
||||
|
||||
// update token
|
||||
localStorage.token = token;
|
||||
window.location.href = '#/volumelist';
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// No token plain login
|
||||
window.location.href = '#/login';
|
||||
});
|
||||
};
|
||||
|
||||
@@ -8,8 +8,8 @@ var app = angular.module('YellowTent', ['acute.select', 'ngRoute', 'ngAnimate',
|
||||
// setup all major application routes
|
||||
app.config(function ($routeProvider) {
|
||||
$routeProvider.when('/', {
|
||||
controller: 'SplashController',
|
||||
templateUrl: 'partials/splash.html'
|
||||
controller: 'LoginController',
|
||||
templateUrl: 'partials/login.html'
|
||||
}).when('/login', {
|
||||
controller: 'LoginController',
|
||||
templateUrl: 'partials/login.html'
|
||||
|
||||
@@ -22,6 +22,8 @@ angular.module('clientService', [])
|
||||
this._username = null;
|
||||
this._userInfo = null;
|
||||
this._token = null;
|
||||
this._clientId = null;
|
||||
this._clientSecret = null;
|
||||
|
||||
this.setToken(localStorage.token);
|
||||
}
|
||||
@@ -40,10 +42,15 @@ angular.module('clientService', [])
|
||||
this._token = token;
|
||||
};
|
||||
|
||||
Client.prototype.getToken = function () {
|
||||
Client.prototype.token = function () {
|
||||
return this._token;
|
||||
};
|
||||
|
||||
Client.prototype.setClientCredentials = function (id, secret) {
|
||||
this._clientId = id;
|
||||
this._clientSecret = secret;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Rest API wrappers
|
||||
@@ -238,30 +245,11 @@ angular.module('clientService', [])
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.tokenLogin = function (oldToken, callback) {
|
||||
$http.defaults.headers.common.Authorization = 'Token ' + oldToken;
|
||||
this._login(callback);
|
||||
};
|
||||
|
||||
Client.prototype.logout = function () {
|
||||
localStorage.removeItem('token');
|
||||
this.setToken(null);
|
||||
this._username = '';
|
||||
this._userInfo = null;
|
||||
};
|
||||
|
||||
Client.prototype.login = function (username, password, callback) {
|
||||
$http.defaults.headers.common.Authorization = 'Basic ' + $base64.encode(username + ':' + password);
|
||||
this._login(callback);
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal login which is wrapped by login() and tokenLogin()
|
||||
* The wrappers setup the auth header
|
||||
*/
|
||||
Client.prototype._login = function (callback) {
|
||||
Client.prototype.login = function (token, callback) {
|
||||
var that = this;
|
||||
|
||||
$http.defaults.headers.common.Authorization = 'Token ' + token;
|
||||
|
||||
$http.get('/api/v1/user/token')
|
||||
.success(function(data, status, headers, config) {
|
||||
if (status !== 200) {
|
||||
@@ -282,5 +270,35 @@ angular.module('clientService', [])
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.logout = function () {
|
||||
localStorage.removeItem('token');
|
||||
this.setToken(null);
|
||||
this._username = '';
|
||||
this._userInfo = null;
|
||||
};
|
||||
|
||||
Client.prototype.exchangeCodeForToken = function (authCode, callback) {
|
||||
var that = this;
|
||||
var data = {
|
||||
grant_type: 'authorization_code',
|
||||
code: authCode,
|
||||
redirect_uri: 'https://localhost',
|
||||
client_id: this._clientId,
|
||||
client_secret: this._clientSecret
|
||||
};
|
||||
|
||||
$http.post('/api/v1/oauth/token?response_type=token&client_id=' + this._clientId, data)
|
||||
.success(function(data, status, headers, config) {
|
||||
if (status !== 200) return callback(new ClientError(status, data));
|
||||
|
||||
that.login(data.access_token, function (error, result) {
|
||||
callback(null, data.access_token);
|
||||
});
|
||||
})
|
||||
.error(function(data, status, headers, config) {
|
||||
callback(new ClientError(status, data));
|
||||
});
|
||||
};
|
||||
|
||||
return new Client();
|
||||
});
|
||||
@@ -2,31 +2,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-3"></div>
|
||||
<div class="col-md-6">
|
||||
<div class="container-fluid">
|
||||
<form class="form-signin" role="form" ng-submit="submit()">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h2 class="form-signin-heading pull-right">Please sing in</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<span ng-show="error.username" class="error show-animate">{{error.username}}</span>
|
||||
<input type="text" class="form-control" ng-model="username" placeholder="Username" required autofocus>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<input type="password" class="form-control has-error" ng-model="password" placeholder="Password" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<input class="btn btn-green btn-block" type="submit" ng-disabled="{{disabled}}" value="Sign in"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="signInButton" class="yellowtent-signin" data-callback="" data-clientid="cid-webadmin" data-requestscopes="*"></div>
|
||||
</div>
|
||||
<div class="col-md-3"></div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user