Couchdb and proxy authentication - couchdb

I have been using couchdb for a long time and we authenticate through cookies auth. Now we would like to start testing proxy authentication but I don't quite understand how it works.
I already have it activated including the value "chttpd_auth, proxy_authentication_handler" in the section "chttpd / authentication_handlers:" but how do I indicate that the token x is for the user y?
I can't understand how it works
I hope someone can help me with an example. Thank you.

In proxy_authentication, you are doing authentication somewhere else. That
somewhere else is a proxy, or to be more specific a reverse proxy.
For example, if you're just using a single user and using nginx as a proxy to
couchdb, you set the required headers before request is passed to couchdb
like:
location / {
# pass to couchdb
proxy_pass http://localhost:5984;
# ... other configurations.
# authentication header
proxy_set_header X-Auth-CouchDB-UserName 'someone';
proxy_set_header X-Auth-CouchDB-Roles '_admin,staff';
proxy_set_header X-Auth-CouchDB-Token 'auth-token';
}
Couchdb will accept request with given username and roles. X-Auth-CouchDB-Token should be a hex encoded hmac of X-Auth-CouchDB-UserName using secret in couch_httpd_auth section in your configuration. It is not required unless proxy_use_secret is true, which is not the case by default (although it should it should be used in production).
In practice, you will need to create a proxy server that validates username
(maybe with password). Only after the user is valid the request will be passed
to couchdb with those headers attached.

Related

How to access "current logged-in user" in remote methods?

recently in one of my applications I needed to access currently logged-in user data for saving in another model (something like the author of a book or owner of a book). in my googling, I encountered these references but none of them was useful.
https://github.com/strongloop/loopback/issues/1495
https://docs.strongloop.com/display/public/LB/Using+current+context
...
all of them have this problem about accessing context or req object. after three days I decided to switch to afterRemote remote hook and add Owner or Author on that stage.
but something was wrong with this solution.
in strongloop's documentations (https://docs.strongloop.com/display/public/LB/Remote+hooks) there is a variable as ctx.req.accessToken that saves current logged-in user access token. but in the application this variable is undefined.
instead, I found accessToken in ctx.req.query.access_token and it was currently access_token variable that is sent to the server.
here is my problem:
is this variable (ctx.req.query.access_token) always available or
it's just because loopback-explorer send access_token as GET
variable?
in production mode do applications need to send access_token as
GET variable or it should be sent as Authorization in the header?
why ctx.req.accessToken is undefined?
could these things change over time? cause most of users encounter this problem due to deprecation of app.getCurrentContext()
Is this variable (ctx.req.query.access_token) always available or
it's just because loopback-explorer send access_token as GET
variable?
Well if your application always sends in the querystring, then it'll be always available for you, but it also sent in the header, or cookie or in the request body, but I don't suggest using it because it if the user logged in and the access token is valid and ctx.req.accessToken should be available and you can use it.
In production mode do applications need to send access_token as
GET variable or it should be sent as Authorization in the header?
I believe Authorization header is preferred, as if you send it in a GET variable, well it'll be visible in the logs and someone with the access to the logs can access the session(well unless you trust everyone), other than this it's fine to have it in a GET variable. Though I believe loopback client SDKs(Angular, Android, iOS) all send it via Authorization header by default, so you might have to configure them(maybe not possible).
Why ctx.req.accessToken is undefined?
Sometimes the context is lost thanks to the database drivers connection pooling, or the context req is lost(ctx.req) and they are null.
Assuming ctx.req is defined(because sometimes it's not), then probably that means the user is not logged it, or it's access token wasn't valid(expired or not in database). Also it could be a bug(maybe misconfiguration on your side), which also means for you that you will authentication problems.
Could these things change over time? cause most of users encounter this problem due to deprecation of app.getCurrentContext()
app.getCurrentContext is risky to use and I don't suggest unless you have no other solution. If you use it and it works, it might stop working if the database driver changes or in some corner cases that you haven't tested it, it might not work.
In the updated doc https://loopback.io/doc/en/lb3/Using-current-context.html
add this in your remoting metadata
"accepts": [
{"arg": "options", "type": "object", "http": "optionsFromRequest"}
]
then
MyModel.methodName = function(options) {
const token = options && options.accessToken;
const userId = token.userId
}
but it says
In LoopBack 2.x, this feature is disabled by default for compatibility reasons. To enable, add "injectOptionsFromRemoteContext": true to your model JSON file.
so add "injectOptionsFromRemoteContext": true on your model.json file

C# LDAP Authentication works for one DC, but not another

I have an interesting issue I've been trying to resolve for a few days.
I'm currently working with an Windows Server 2003 machine that is running a standard instance of Active Directory.
The directory contains two domain components (DCs) that both house users that are going to be authorizing against the directory, via my application.
I'm using :
The IP address of the server as the host name
An SSL connection via port 3269
The GSS Negotiate Auth Mechanism
A BaseDN that is a parentDN of both DC's
The sAMAccountName as the login name
The problem is, I cannot successfully authorize any users from DC1, yet all of the ones who belong to DC2 are completely fine and work great. I get this error on DC1 :
8009030C: LdapErr: DSID-0C09043E, comment: AcceptSecurityContext error, data 0, vece
System.DirectoryServices.Protocols.LdapException: The supplied credential is invalid.
However, using Softerra's LDAP Broswer, I can connect in and authorize the same exact user without any issue, so I know the credentials are correct.
From what I can tell, both of these DC's are configured the same... I've browsed both of them for something, anything that is different... but have found nothing that really stands out.
I posted something months ago about this particular setup, and the code I'm using is in that thread as well.
Set callback for System.DirectoryServices.DirectoryEntry to handle self-signed SSL certificate?
Any help here would be much appreciated.
Thanks!
I was able to get this working, but for the life of me I cannot figure out why this was the case. Basically, this error...
8009030C: LdapErr: DSID-0C09043E, comment: AcceptSecurityContext error, data 0, vece System.DirectoryServices.Protocols.LdapException: The supplied credential is invalid.
...was dead on. The issue was that users logging in under what I called DC2 needed to issue the bind with the domain AND sAMAccountName (Ex. LIB\JSmith), as opposed to DC1, which allowed just the sAMAccountName to be entered.
I figured the best way to make this programmatic was to use the principal binding account to query for the DN of the user. From that DN, using some crafty RegEx, I'm able to capture the domain they inherit from, and issue two separate binds.
SearchResultEntry ResultEntry = userResponse.Entries[0];
//Let's get the root domain of the user now using our DN RegEx and that search result
Regex RegexForBaseDN = new Regex(config.LdapAuth.LdapDnRegex);
Match match = RegexForBaseDN.Match(ResultEntry.DistinguishedName);
string domain = match.Groups[1].Value;
//Try binding the user with their domain\username
try
{
var thisUser = new NetworkCredential{
Domain = domain,
UserName = username,
Password = Pin
};
//If this goes well, we'll continue forward
ldapconn.Bind(thisUser);
}
//If that doesn't work, try biding them with the highest level domain
catch (LdapException ex)
{
if (ex.ErrorCode.Equals(LdapErrorCodes.LDAP_INVALID_CREDENTIALS))
{
var thisUserOnce = new NetworkCredential{
Domain = config.LdapAuth.LdapDomain,
UserName = username,
Password = Pin
};
//If this goes well, we'll continue forward
ldapconn.Bind(thisUserOnce);
}
}
It's not nearly as elegant as I would have wanted, but it does work for this particular scenario.
However, I'm still really interested in why the naming conventions are different depending on which DC the user inherit's from.

xmpp Opera throws security error

gurus of programming!
I had created some chat, based on the book "XMPP programming", so I've included strophe.js and gab.js in my project. Everything is fine, service is working both in IE and Firefox. But not Opera, Opera in this case throws an exception
Uncaught exception: ReferenceError: Security violation
Error thrown at line 2554, column 16 in <anonymous function: _processRequest>() in http://chat.aviportal.com/strophejs/strophe.js:
req.xhr.send(req.data);
called from line 2566, column 16 in <anonymous function: _processRequest>(i) in http://chat.aviportal.com/strophejs/strophe.js:
sendFunc();
called from line 2607, column 12 in <anonymous function: _throttledRequestHandler>() in http://chat.aviportal.com/strophejs/strophe.js:
this._processRequest(0);
called from line 2709, column 16 in <anonymous function: _onRequestStateChange>(func, req) in http://chat.aviportal.com/strophejs/strophe.js:
this._throttledRequestHandler();
Please let me know if anyone had similar problems, or maybe, I'll listen to your advices.
Thanks beforehands, Alex
Edited:
Ok, first of all, thanks for replying!
$(document).ready(function() {
var conn = new Strophe.Connection(
'http://chat.aviportal.com:5280/xmpp-httpbind');
conn.connect('guest2#chat.aviportal.com', 'passwd', function (status) {
if (status === Strophe.Status.CONNECTED) {
$(document).trigger('connected');
} else if (status === Strophe.Status.DISCONNECTED) {
$(document).trigger('disconnected');
}
});
This is how I initialialize the strophe connection, the process bangs on conn.connect('guest2#chat.aviportal.com', etc)
The exception is thrown on that line.
BTW, what is CORS, Cross Domain Requests? The ejabberd on the same subdomain as the php file, so I don't think, but, there is a small possibility that it is ^_^
Despite your webserver running on the same domain as ejabberd, accessing a different port DOES constitute a cross domain request and should raise a security exception. So, connecting to domain:5280 is not the same as domain:80.
To solve this easily you should include a proxy on your setup. Most likely you already have apache or nginx in front, so you should just proxy domain:80/http-bind to go to domain:5280. For example for nginx you should have something like:
location /http-bind {
proxy_buffering off;
tcp_nodelay on;
keepalive_timeout 55;
proxy_pass http://localhost:5280;
}
in your nginx.conf.
You can fix this without Jquery too !
Add following in the header of the file from where you are fetching the data:
Access-Control-Allow-Origin: *
Try placing this in your file if the libraries you are using are jQuery-based:
jQuery.support.cors = true;
This error is caused by Opera blocking a cross-site request. CORS will allow cross-site requests to be made from a normal web page if the server-side script allows it. Read more here.
Currently, Opera only allows cross-site requests inside extensions as long as you specify it in the config.xml file. Even so, however, if you try to use jQuery in an extension to make an XSS request, you will get a security violation unless you include in the file the line I mentioned at the beginning.

Ibrowse Erlang HTTP Client Proxy Authentication within a Domain

My Ibrowse HTTP Client is behind a Network and any HTTP request to the outside has to go through a Proxy. Now, Ibrowse has a good example for this. However, i got a little confused. The Proxy behind which i am running the application uses Domain Authentication (this Domain is an Active Directory kinda setup) whereby usually in a browser we would have to enter settings like this (say the domain is "kyaug"),
username: kyaug\[YOUR_DOMAIN_USERNAME]
password: [Domain Password]
This means that [YOUR_DOMAIN_USERNAME] is your Domain Username actually.
Now in the Ibrowse, an example that looks like this comes along:
ibrowse:send_req("http://www.erlang.se/", [], get, [],
[{proxy_user, "XXXXX"},
{proxy_password, "XXXXX"},
{proxy_host, "proxy"},
{proxy_port, 8080}], 5000).
Now, lets say that my situation is as follows:
Domain: kyaug
Domain Username: muzaayj
Proxy Server: ppi.kyu.co.ug
Proxy Port: 3128
Domain Password: xxxxx
Now, When i try thsi below:
Options = [
{proxy_user, "kyaug\muzaayj"},
{proxy_password, "My Domain Password"},
{proxy_host, "ppi.kyu.co.ug"},
{proxy_port, 3128}
],ibrowse:send_req("http://www.google.com",[],post,Data,Options,infinity).
The proxy spits back to me an HTML page informing me that PROXY_AUTH_REQUIRED and many other things about its administrators. Now, i have a feeling that its because i am putting the proxy_user wrongly. In the above, i am supplying this parameter the way the browsers take it as well, probably behind the scenes, its changed into a different arrangement. Some one assist in how i can correct this. How do browsers send their data to a proxy server for authentication given that the username must be append to the Domain to be used for authentication at the Proxy end ?
Have you tried {proxy_user, "muzaayj"} in the options instead of {proxy_user, "kyaug\muzaayj"}?
Have you tried {proxy_user, "kyaug\\muzaayj"}? A single backslash escapes the m back to an m, but a double backslash becomes a single backslash in the string.
I am not familiar with ibrowse, but i think that problem in windows authentication method (ofc it depends on AD config, but i suspect that is NTLM Auth) which ibrowse doesnt supprot.

How to connect SproutCore to CouchDB in Mac OSX

I am using SproutCore to query a CouchDB database on Mac OSX (10.6.7), from a tutorial on NetTuts+ premium. The database name is microblog. The query resolve to this string:
"http://localhost:5984/microblog/_design/posts/_view/posts?descending=true"
If I type this query directly in the browser's address bar, I get a nice json answer. But through the SproutCore app, I get an error message:
405 Method Not Allowed
Why is that? would that be because SC is running out of :4020 and CouchDB out of :5984 ? Any ideas?
Because of Javascript cross-domain regulations you are not allowed to query any arbitrary URL from your browser. If you loaded your sproutcore page from localhost:4020, it's forbidden to contact any other host or port on the same host.
To overcome this problem you usually make your sproutcore host proxy to the backend. You can do this by including a proxy statement like the following in your sproutcore buildfile
proxy "/microblog", :to => "localhost:5984"
which will forward all request going to localhost:4020/microblog to your backend localhost:5984/microblog. As you can imagine this might lead to problems where you can't set the url in your sc application to the desired value, the common case might be that your sc application is also named "microblog" the above proxy directive would then cause your sc application url being overridden.
To fix that problem you can use another url in your sc application to contact the backend, e.g. /db and then use the url parameter in the proxy directive to rewrite the target url:
proxy "/db", :to => "localhost:5984", :url => "microblog"
All requests to localhost:4020/db will then be forwarded to localhost:5984/microblog and will no longer interfere with your sc application on localhost:4020/microblog.

Resources