arcath / adauth Goto Github PK
View Code? Open in Web Editor NEWA Ruby interface for Microsoft's Active Directory based off ruby-net-ldap
Home Page: http://adauth.arcath.net
License: MIT License
A Ruby interface for Microsoft's Active Directory based off ruby-net-ldap
Home Page: http://adauth.arcath.net
License: MIT License
Is there a way to add a secondary domain server to the adauth.rb file?
i.e. in the lines :
# The IP address or Hostname of a DC (Domain Controller) on your network
This could be anything and probably wont be 127.0.0.1
Again contact your IT Support if you can't work this out
c.server = "10.0.0.25"
so that I could do something like
c.server = "10.0.0.25", "10.0.0.26"
If this is a current capability, how do you do it? If not, can it be added?
thanks
I see how to change a password. Person needs to be authenticated? We're trying to setup a reset password where the person does not know his/her password and is not logged in. Thanks for any info!
Currently the βlastβ tag is v2.0.5. Could you please add the tag v2.0.6?
How do I include other AD fields when creating a local User? For example, I want to grab a user's email address and save it so I can send emails, but it looks like return_and_create_with_adauth
only grabs and creates a record with login
, group_strings
, ou_strings
, and name
β¦
I've been having an odd issue with adauth in production vs development. There's a bit of background so I'll try and explain.
When running in dev, there are no issues signing in to the app at all - it works fine.
However, when running in production some users can only sign in the first time they ever use it - subsequent sign-ins fail. Specifically, they can only sign in if there is no user record for them in the users database table.
The background:
We had an issue a while back (I think I mentioned it here) where there was an unrelated error (uncaught exception I'd call it). We worked around it by wrapping the code in the sessions_controller in a try catch block. This worked fine, but it ended up masking this problem. Having removed the try/catch I can now see exactly what the issue is.
When the user signs in the first time, a record is created for them in the users table. For some reason group_strings is being set to this (or similar depending on the user):
"---
- !ruby/string:Net::BER::BerIdentifiedString |-
U1NMIFZQTiBVc2Vycw==
- !ruby/string:Net::BER::BerIdentifiedString |-
QXBwX1NoYXJlcG9pbnRfS25vd2xlZGdlVXBkYXRlcnM=
- !ruby/string:Net::BER::BerIdentifiedString |-
RGVwdF9JVA==
- !ruby/string:Net::BER::BerIdentifiedString |-
RXZlcnlvbmUgT3V0bG9vaw==
- !ruby/string:Net::BER::BerIdentifiedString |-
RG9tYWluIEFkbWlucw==
- !ruby/string:Net::BER::BerIdentifiedString |-
RW50ZXJwcmlzZSBBZG1pbnM=''
This doesn't look right at all. ou_strings is set to something reasonable though:
"---
- Users
- IT
- Department
- HO"
The problem occurs on subsequent logins, where we now get an internal server error (now we've removed the try/catch anyway):
ActiveRecord::StatementInvalid (TinyTds::Error: String or binary data would be truncated.: EXEC sp_executesql N'UPDATE [users] SET [group_strings] = ''<that load of string up above>
So the column is a varchar(255) and the group_strings is too large to fit, so an error is thrown.
For now, I am increasing the column size, but I'd love to know why the group_strings looks so odd.
I've tried 2.0.1 and 2.0.2 as well as pulling from git master, all the same.
Arcath / Adauth may well be affected by issue ruby-ldap/ruby-net-ldap#258 given it's built using it. Options to fix:
Old, closed but related issue #43
@Arcath, I have a suggestion and wanted to run it by you before I invest any time in this. When working on specs I generally prefer to mock out external systems as a) it's too much of a hassle to work with a real AD, b) I don't want to screw up and run tests against a real AD system, and c) it's hard to fake issues with that ext. system.
Have you thought about mocking the Net::LDAP call(s), and replacing them with fakes? This could get to be a hassle to do for the tests, but it may not. I can spend a few mins looking into it, but if you're against the idea and would reject the pull request, I won't.
Thanks for providing the gem, I tested it out in a script and it looks good. jz
Aswell as allowed_groups which acts like a white list of groups allowed to login there should be "deny_groups" which is a black list of groups which aren't allowed to login.
It would be helpful if the conversation adauth has with the AD sever could be logged, perhaps a config option to turn it on or off (per environment) which would get adauth to output some useful debugging to the log/console
Can I disable the log?
I am updating an app that I built about two years ago with this gem. All I need to do is authenticate a password against a username. This was easy before (no query_user needed). I don't want to ask the IT department to create a system user that I will have to hard code in my app (when they ask me why I need one now when I don't need one for the old version I don't have a good answer).
So why is query_user required now and is there a way around this?
My OU Structure is:
Company
| - OU1
| - User
Calling .ous on the user only returns an array of ["OU1"]
not ["OU1", "Company"]
.
When using ruby 1.8 the data is presented correctly. When using ruby 1.9 I am seeing this type of behavior
User id: 2, name: "["Matthew Black"]", login: "["mblack"]", first_name: nil, last_name: nil, email: nil, groups: nil
Where as ruby 1.8 it will be like this
User id: 2, name: "Matthew Black", login: "mblack", first_name: nil, last_name: nil, email: nil, groups: nil
When retrieving objectguid the data is modified.
This happens in handle_field at
return (@ldap_object.send(field)to_s).gsub(/\"|\[|\]/, "")
by changing it to
return @ldap_object.send(field).first.to_s
it fixes my problem however i use very few fields.
Although Adauth has tests for all its code they aren't laid out very well and a lot of advanced functionality is tested in the same file as making sure we can fetch a user.
Before 2.1.0 I would like to move them all around and seperate them out into meaningfully named files and folders
There should be a generator that creates a basic version of the initializer with "example.com" and descriptive comments.
Hi,
I was wondering whether it would be possible to make adauth do some kind of "remember me" thing?
I'd like to be able to let our users log in & then be auto-logged in next time (for some set period of time), kinda like how devise allows you to do. Currently the session cookie that is set expires on browser close (so they are asked to log in next time).
I don't know whether this is something that adauth could/should handle, or whether it is something I would need to do in my app specifically (if so, have you any pointers on how?)
Thanks,
James
As I understand the purpose of simple_authenticate is authenticating a user against the domain without requiring a query user. This is not happening, as per sequence below:
Adauth::AdObjects::User.simple_authenticate(usr, pwd)
allowed_to_login
usr.cn_goups_nested
Adauth::AdObjects::Group.where('name', group)
filter
Adauth.connection
connect
_Adauth::Connection.new(connection_hash(
_@config.query_user, @config.query_password
_))
This happens because Adauth.connection
doesn't return a connection, despite there's an existing one
created by Adauth::AdObjects::User.authenticate
to authenticate the user against the AD; Adauth.connect
therefore tries to establish a new connection with the query user credentials, which will be empty, resulting in a <Net::LDAP::LdapError: invalid binding information>
error.
The tests themselves simple_authenticate the query user, which kind of defeats the whole purpose of it.
Imho the simplest approach to solve this would be to change Adauth.connection_hash
in order to use provided credentials if no query user is configured:
accept empty user and password arguments by default (user = "", password = "")
use those values as fallback when no query user is configured, in the likes of
:username => @config.query_user.blank? ? user : @config.query_user,
:password => @config.query_user.blank? ? password : @config.password
In this line, would also need to change:
Adauth.connection
, in order to accept empty user and password arguments by default (user = "", password = ""
)Adauth.connect
Some configuration examples should be provided in the wiki.
Examples I think are needed
Some companies will only use gems with a certain license.
The canonical and easy way to check is via the gemspec
via e.g.
spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']
There is even a License Finder to help companies ensure all gems they use
meet their licensing needs. This tool depends on license information being available in the gemspec.
Including a license in your gemspec is a good practice, in any case.
How did I find you?
I'm using a script to collect stats on gems, originally looking for download data, but decided to collect licenses too,
and make issues for missing ones as a public service :)
https://gist.github.com/bf4/5952053#file-license_issue-rb-L13 So far it's going pretty well
My company has federated its on-premises Active Directory server with Microsoft Office 365 in the cloud. Are there any configuration considerations to take into account when trying to authenticate against it? Is it even supported?
Hey there,
I can't get ruby-net-ldap (latest version I get is 0.0.4) to connect to my legacy Windows 2000 Server's AD, however net-ldap (0.2.2 here) works fine.
Is there a specific reason why the former is a dependency of your gem, and not the latter?
As it is, your gem just won't work for me :-/
Best,
At the moment if the LDAP server is unavliable Adauth takes 20-30 seconds to return an invalid login, would be alot better if it caught the error after 10 seconds and returned a message asking the end user to contact IT support (all changable of course)
There is an issue where if a user is associated with a large number of groups the time required to login when simple_tls is enabled is greatly increased. The average response time for a user with 100 group memberships is around 1 second when simple_tls is not in use. However, when it is in use the time escalates to 20+ seconds for a login.
I believe this is caused by the amount of repeated queries that is done combined with the overhead of simple_tls.
For each group membership there are an additional four queries -- two group queries and two user queries. A user with 100 group memberships generate 500 queries. The interesting thing is that the additional four queries seem irrelevant, the first query is against a null user/group. The second set of queries is against a seemingly random user that is a member of the group.
Searching for all "(objectClass=user)" where sAMAccountName = user_a
Connecting to AD as "ad_user"
Searching for all "(objectClass=group)" where name = group_a
Searching for all "(objectClass=user)" where sAMAccountName =
Searching for all "(objectClass=group)" where sAMAccountName =
Searching for all "(objectClass=user)" where sAMAccountName = user_b
Searching for all "(objectClass=group)" where sAMAccountName = user_b
Searching for all "(objectClass=group)" where name = group_b
Searching for all "(objectClass=user)" where sAMAccountName =
Searching for all "(objectClass=group)" where sAMAccountName =
Searching for all "(objectClass=user)" where sAMAccountName = user_c
Searching for all "(objectClass=group)" where sAMAccountName = user_c
...
(500 lines)
Is it possible to configure this gem to store additional fields in the database, such as the user's email address?
I have tried looking around for an answer to this question but haven't been able to find an answer.
I'm having a problem with groups over 1500 members... Apparently they only return the first 1500 members and as a different field leaving the member array empty, which causes problems..
:member=>[], :"member;range=0-1499"=>[blah blah blah]
Any idea how to get around this?
I ran the following command
rails g adauth:sessions
Which as the documentation states,
adds a couple of routes, a sessions controller and a login form
How do I change the style of the login form? I can't find where it's located
Needs support for LDAP over SSL please
Currently it is assumed that givenname
is set, which is not always the case. Itβd be great if the code could check for that.
Once inssue #12 is sorted there isn't any real need for the developer to have to workout the LDAP base string. It would be relatively easy to work it out off c.domain.
I've been using AdAuth in a couple apps for awhile and recently upgraded one to 2.0.3 and most of my users are fine, but for one particular user I'm getting an error in the above mentioned line about not being able to split nil. The relevant part of the stack trace:
adauth (2.0.3) lib/adauth/ad_objects/group.rb:51:in cn_groups' adauth (2.0.3) lib/adauth/ad_object.rb:111:in
block in cn_groups_nested'
adauth (2.0.3) lib/adauth/ad_object.rb:109:in each' adauth (2.0.3) lib/adauth/ad_object.rb:109:in
cn_groups_nested'
adauth (2.0.3) lib/adauth/authenticate.rb:26:in allowed_to_login' adauth (2.0.3) lib/adauth/authenticate.rb:10:in
authenticate'
app/controllers/sessions_controller.rb:8:in `create'
I've checked and the user is pretty much in the same groups as another user with similar groups. I assume that there's something misconfigured in her AD account, I just can't seem to figure out what.
When using rails 3.1 rails s
returns this error when adauth is in the gemfile
asset_paths.rb:66: uninitialized constant ActionView::Helpers::AssetTagHelper::AssetPaths::Mutex (NameError)
Now that Adauth 2.0.0 can find out anything about active directory and modify fields it makes sense for it to be able to reset paswords.
This isn't as simple as performing a replace on password as it needs to be hashed and supplied in an odd way I havent worked out yet. Once i do it will most likely end up in Adauth::AdObjects::User.reset_password()
Instead of the having the developer write the code for the views, controllers and models Adauth should provide defaults that can be overridden. This would mean providing the current_uesr method and the SessionsController in Adauth aswell as the generators to create the correct files.
I don't think the functionality of the controllers should be provided by middleware as it will be a lot easier for developers to change the functionality if they just change a generated controller, instead of having to over ride middleware.
At the moment it is not possible to filter on multiple items eg. allowed_groups and denied_ous. You basically have to fit it all into one of the arrays.
If for what ever reason you simply want to log a user in without checking credentials (possibly a guest user) to keep the details you will need to be bale to run the normal authentication process without the password for that user.
This is part of the solution to issue #10
We've noticed that it's possible to login using adauth by supplying a correct username & a blank password. We've seen the following:
correct username & correct password -> login
correct username & incorrect password -> fail
correct username, & blank password -> login (as username)
incorrect username & [correct|incorrect|blank] password -> fail
This is even for users who are NOT currently in the users table (ie have never previously logged in).
Currently using the latest git master branch (pulled from git today using bundle update):
https://github.com/Arcath/Adauth.git
Setup is like this (boring bits omitted):
initializers/adauth.rb
c.doman = "domain.local"
c.query_user = "<a low privilege account>"
c.query_password = "****"
c.server = "10.0.0.1"
c.base = "dc=domain, dc=local"
models/user.rb
class User < ActiveRecord::Base
include Adauth::Rails::ModelBridge
AdauthMappings = {
:login => :login,
:group_strings => :cn_groups,
:ou_strings => :dn_ous,
:email => :email,
:name => :name
}
AdauthSearchField = [:login, :login]
controllers/sessions_controller.rb
def create
begin
ldap_user = Adauth.authenticate(params[:username], params[:password])
if ldap_user
user = User.return_and_create_from_adauth(ldap_user)
session[:user_id] = user.id
redirect_to <somewhere nice> and return
else
redirect_to <a bad place> and return
end
rescue
redirect_to <an even worse place> and return
end
end
def new
redirect_to root_path if current_user
end
We added the begin/rescue/end in the create session because we encountered an error when giving incorrect usernames/passwords (ldap_user was true even for bad usernames - like logging in as asdf/crap_pass)
Removing the rescue still lets you log in without a password, and errors if the username or password is incorrect (but not blank), ie it being there has no effect on this issue, but it does prevent an error.
What's going on?
Oh, an excerpt from the users table:
id: 18
login: james
group_strings: --- - !ruby/string:Net::BER::BerIdentifiedString |- U1NMIFZQTiBVc2Vycw== - !ruby/string:Net::BER::BerIdentifiedString |- QXBwX1NoYXJlcG9pbnRfS25vd2xlZGdlVXBkYXRlcnM= - !ruby/string:Net::BER::BerIdentifiedString |- RGVwdF9JVA== - !ruby/string:Net::BER::BerIdentifiedString |- RXZlcnlvbmUgT3V0bG9vaw== - !ruby/string:Net::BER::BerIdentifiedString |- RG9tYWluIEFkbWlucw== - !ruby/string:Net::BER::BerIdentifiedString |- RW50ZXJwcmlzZSBBZG1pbnM=
name: James
ou_strings: --- - Users - IT - Department - CompanyHO
email: [email protected]
Not sure whats going on with group_strings(!) or ou_strings, but I don't currently use them for anything.
This user logged on by providing username "james" and no password
I'll admit I haven't tried doing this, not entirely sure how to begin.
Is it possible to re-validate an already signed in users' password?
Example:
A user has signed in successfully. Now they want to visit a more sensitive area of the site, I would like them to re-type their password again before allowing them to proceed.
Despite having the following in config/initializers/adauth.rb
c.allowed_ous= ["OU1", "OU2"]
members from other organizational units are matched too.
Is there a way to test if that is an AD configuration error or an Adauth error?
There's a boundary case that isn't handled cleanly, which is when allowed_groups
is configured but the user attempting to authenticate isn't defined in any specific AD groups at all. In this case 'memberof' isn't defined in the returned Net::LDAP::Entry object. I know little about AD administration so I'm not sure how likely this is in practice, but I just hit it while testing against an internal dev AD instance.
Ideally of course, the behavior should be the same -- if you're not a member of any groups, then you're not a member of the allowed group(s) and authentication is denied.
Adauth::UserModel.return_and_create_with_adauth should update all the users details so that changes to groups etc... get synced across.
At the moment Adauth only fetches the information it needs to authenticate and create the user record. It would be better if a developer could set a config option that returned additional details such as:
c.ad_attrs = ["email", "phone_number", ...]
So their application can send out emails etc...
Altering the base string to do OU filtering is a bit constricting as a structure of
Base
IT
Dev
Mangement
would only allow you to limit to one of those OUs, if you wanted to limit to both IT and Dev you would need to change your structure or add some security groups. It would be a lot better if there was a multi value attribute that returned an array of the OUs a user is a member of allowing for the same filtering as groups
i get the response
extra Add this code to your ApplicationController
helper_method :current_user
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
and then it stops
any resolutions?
These shiny generators are great but its time to document them before a 1.0.0 release
Because rails3.1 migrations use a "migrate" method not "up" and "down" methods the generated migration doesnt work.
Need to swap to using the migration generator to generate the migration so its not tied to a specific version of rails
In lib/adauth/authenticate.rb
the code below is going to result in a βcrashβ when the search result is empty.
user = Adauth::AdObjects::User.where('sAMAccountName', username).first
if allowed_to_login(user)
Adauth.logger.info("authentication") { "Authentication succesful" }
return user
else
Adauth.logger.info("authentication") { "Authentication failed (not in allowed group or ou)" }
return false
end
Calling the method first
on the empty result, results in user being nil
, which causes failures further down the path. Could a check be added, so that false
is returned if user
is nil
.
Even better would be to return more error codes or even messages, which can then be displayed in the log-in dialog.
I'm not sure, but I think that there is an error in the documentation at https://github.com/Arcath/Adauth
The code on the page was
class User < ActiveRecord::Base
include Adauth::Rails::ModelBridge
AdauthMappings = {
:login => :login
:group_strings => :cn_groups
}
AdauthSearchField = [:login, :login]
end
The code I used after getting an error was
AdauthMappings = {
:login => :login,
:group_strings => :cn_groups
}
AdauthSearchField = [:login, :login]
I had to put a comma after login.
If the posted code is correct, I apologize.
As described in ruby-ldap/ruby-net-ldap#44 this problem has been fixed in a fork of net-ldap.
I will be thinking about how to move adauth forward with one of its dependencies seemingly abandoned.
As bought up on reddit by mikefh.
When pitching a Rails solution for intranet projects, I've regularly hit the same hurtles... some person always pitches SharePoint because of the ability to "pickup on the user currently logged into the Windows PC." I was hoping that Adauth could assist this exact point.
I'm not really sure how this could work but its worth looking to see if there is someway Adauth can be used to provide this functionality.
My current line of thinking is that share point must use some kind of javascript or activex object to pickup on the user via some kind of token that can't be forged, so if that could be passed to adauth somehow then it maybe possible to find the current user.
I'm not assigning this to 1.1.0 (yet) until I have some idea how to achieve it but any input on this issue would be greatly appreciated.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.