Comments (11)
me too, +1
from angular-digest-auth.
+1
i'm picking up legacy code (don't usually use angular), need to get digest auth working, all angular stackoverflows point to this lib but can't figure out how the hell we go from including the module to having a dgAuthService available for the controllers to use.
working example code would be really useful.
from angular-digest-auth.
I got this working (for the most part), and wanted to share my solution in case it helps others. It took a bit of understanding Digest Authorization and making a few changes to the angular-digest-auth.js file.
First off, I looked at the RESPONSE header from our server, which was already set up for digest authentication:
Authenticate: Digest realm="concordUI", nonce="66fe7765"
Connection: keep-alive
Content-Length: 0
This told me two things:
- To pass
Authenticate
as the header to dgAuthServiceProvider.setHeader - That our server is using RFC 2069, which is basically 'Level 1' Digest Authentication, according to the Wiki ([https://en.wikipedia.org/wiki/Digest_access_authentication]).
Looking at tafax's angularJS digest code, it is set up for 'Level 2' Digest auth (RFC 2617), so it will include the nonceCount and qop in the HASH response. This isn't compatible with RFC 2069, so I had to edited out those parts in his code (generateResponse and generateHeader functions). For the generateResponse function, my 'return' code followed the RFC 2069 standard:
return md5.createHash(ha1 + ":" + authServer.info.nonce + ":" + ha2);
In the generateHeader function, I removed the algorith, opaque, qop, and nc lines. I may have been able to keep them in, but I took them out just to be safe. The modfied generateResponse method ignores the nc and cnonce values. I left them in just in case we end up doing 'Level 2'/RFC 2617 in the future.
In my app, I configured the dgAuthServiceProvider like this:
app.config(['dgAuthServiceProvider', function(dgAuthServiceProvider) {
dgAuthServiceProvider.setHeader('authenticate');
dgAuthServiceProvider.setLimit('inf');
dgAuthServiceProvider.setConfig({
login: {
method: 'GET',
url: '/con/data/userList' //Some URL which requires authentication
},
logout: {
method: 'GET',
url: '/con/data/userList' //Some URL which requires authentication
}
});
dgAuthServiceProvider.callbacks.login.push(['AuthenticationSvc', function(AuthenticationSvc)
{
return {
successful: function(response)
{
AuthenticationSvc.loginSuccessful(response);
},
error: function(response)
{
AuthenticationSvc.loginError(response);
},
required: function(response)
{
AuthenticationSvc.loginRequired(response);
},
limit: function(response)
{
AuthenticationSvc.loginLimitReached(response);
}
};
}]);
dgAuthServiceProvider.callbacks.logout.push(['AuthenticationSvc', function(AuthenticationSvc)
{
return {
successful: function(response)
{
AuthenticationSvc.logoutSuccessful(response);
},
error: function(response)
{
AuthenticationSvc.logoutError(response);
}
};
}]);
}]);
I created my own service, 'AuthenticationSvc', to handle all the responses from the digest service, including login and logout functions:
(function() {
'use strict';
angular
.module('myApp')
.factory('AuthenticationSvc', AuthenticationSvc);
AuthenticationSvc.$inject = ['$q', '$timeout', 'dgAuthService'];
function AuthenticationSvc( $q, $timeout, dgAuthService) {
var service = {
//Functions
start: start,
login: login,
logout: logout,
loginSuccessful: loginSuccessful,
loginError: loginError,
loginRequired: loginRequired,
loginLimitReached: loginLimitReached,
logoutSuccessful: logoutSuccessful,
logoutError: logoutError,
//Variables
isLoggedIn: false
};
var qLogin = null;
var qStart = null;
var qLogout = null
//These help differentiate between starting (and automatically logging in from previous creds) and manually logging in
var bStarting = false;
var bManualLogIn = false;
return service;
// implementations //
function start() { //Used when user first hits the web site - Starts the auth service
qStart = $q.defer();
$timeout(function() {
//Start auth service if it hasn't already started
if (dgAuthService.hasStarted()) { //Already started, so just resolve the qStart
qStart.resolve();
} else {
bStarting = true;
dgAuthService.start();
}
});
return qStart.promise;
}
function loginSuccessful(response) {
service.isLoggedIn = true;
if (bStarting) {
bStarting = false;
qStart.resolve();
}
if (bManualLogIn) {
bManualLogIn = false;
qLogin.resolve();
}
}
function loginError(response) {
response.errorType = 'loginError';
if (bStarting) {
bStarting = false;
qStart.reject(response);
}
if (bManualLogIn) {
bManualLogIn = false;
qLogin.reject(response);
}
}
function loginRequired(response) {
response.errorType = 'loginRequired';
if (bStarting) {
bStarting = false;
qStart.reject(response);
}
//No bManualLogIn check here because if we get to this state we've started but not logged in
//from previous session, which is fine. We want to keep 'bManualLogIn' value as it is
}
function loginLimitReached(response) {
response.errorType = 'loginLimitReached';
if (bStarting) {
bStarting = false;
qStart.reject(response);
}
if (bManualLogIn) {
bManualLogIn = false;
qLogin.reject(response);
}
}
function logoutSuccessful(response) {
service.isLoggedIn = false;
qLogout.resolve();
}
function logoutError(response) {
qLogout.reject(response);
}
/**
* Do user login
* @param credentials (object) {username (string) - username, password (string) - password}
*/
function login(credentials) {
qLogin = $q.defer();
bManualLogIn = true;
$timeout(function() {
service.start().finally(function() { //Start the service in case it hasn't started yet (user browsed directly to login page)
if (service.isLoggedIn) { //We're logged in so we need to logout and then log back in
service.logout().finally(function() {
dgAuthService.setCredentials(credentials.username, credentials.password);
dgAuthService.signin();
});
} else { //Not currently logged in, so log in
dgAuthService.setCredentials(credentials.username, credentials.password);
dgAuthService.signin();
}
});
})
return qLogin.promise;
} //End of function login
/**
* Do user logout
*/
function logout() {
qLogout = $q.defer();
$timeout(function() {
dgAuthService.signout();
});
return qLogout.promise;
} //End of function logout
} //End of AuthenticationSvc
})();
In my router code, I use a resolve which uses the above AuthenticationSvc methods to start the service and routes to a login page if the user isn't already logged in. The login page calls the AuthenticationSvc's login function when the user presses the Login button.
The login/logout functions use promises, so I use AuthenticationSvc.login(creds).then
.... in my Login page.
You might need to add this before the $httpProvider.interceptors.push([
in
the angular-digest-auth.js
file:
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
This prevents the browser from displaying it's own username/password box.
Also, if you add that line, you might actually need to NOT add it (and the auth headers) when browsing off-site to a third party (like google). You'd handle that case in the 'request': function(request)
property function of $httpProvider.interceptors.push.
I hope this helps someone, and I'm not too off base. But that's what I had to do to get it
working on the server we have.
BIG PS: A big thanks to tafax for writing the library. Digest Authentication is non-trivial, and he did a great job on the code! So thank you!!
from angular-digest-auth.
I know this is a very late comment , but
Where the dgAuthService.hasStarted() gets defined? Looking through the source code isn't defined anywhere. Where it comes from?
from angular-digest-auth.
@develmts : Sorry. I added it directly to the DgAuthService function in the angular-digest-auth.js file:
function DgAuthService($q, authIdentity, authRequests, stateMachine)
{
/**
* Specifies if the service is started.
*
* @type {boolean}
* @private
*/
var _started = false;
this.hasStarted = function() {
return _started;
}
.......
}
I actually modified the file a lot to customize what I needed, but hopefully that's the only missing piece for this example.
Hope this helps!
-Scott
from angular-digest-auth.
Thanks !
from angular-digest-auth.
I just started working with this, but not able to do work, getting 401 unauthorized every time. @firrib Can you share your customised angular-digest-auth.js so that it will be helpful to me to resolve the issue
from angular-digest-auth.
@Bhimisetty : Sorry it's for a company I'm working for. I'm not comfortable doing that. Plus, I've made a lot of changes that are very specific to what I'm doing. I wish you luck, though. Perhaps it's on the server end?
from angular-digest-auth.
@firrib Thank you for providing us with the samples !!
from angular-digest-auth.
@kimyearho You're most welcome!
from angular-digest-auth.
Can not hide username / password display box Is there any other alternative?
from angular-digest-auth.
Related Issues (20)
- dgAuthService.start() and POST without username and password data HOT 2
- How to use a controller method to authenticate? HOT 3
- TypeError: header.split is not a function HOT 2
- Support npm installs HOT 1
- Can this module support a standard http-digest exchange which uses WWW-Authenticate? HOT 2
- angular-cookies dependency: is it really used?
- tests seem to fail? HOT 2
- WWW-Authenticate challenge may be parsed incorrectly HOT 1
- authIdentity.get() is not always the information obtained from the signin URL
- Logout keeps credentials
- Is this module still being supported?
- Error in value pattern
- Cross Domain calls not working, every time 401 only getting even though Authorization header is added
- Error when start() method is called HOT 4
- This doesn't seem to follow the protocol for http digest or am I missing something? HOT 1
- using scope in callback HOT 2
- Calling Post on Start Up HOT 1
- Documentation could be better. HOT 2
- Storage of username and password in local storage is insecure.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from angular-digest-auth.