How to validate the active directory domain my app is running in? - vb.net

I have a VB.Net Application that authenticates using the current Windows User without asking for the password. It checks that this user is a member of "MYDOMAIN\ApplicationUsers" before it starts up.
How to check if this is the real domain and not a different one using the same name? Are there any certs or public keys to validate locally? I'd prefer to check this offline, without a third party machine or database etc.
In the System.DirectoryServices.ActiveDirectory Namespace are some Trust an Validate methods but they only seem to check inter domain trust and using a domain name only.

Your problem is that you are using strings and strings like mydomain/application users are not unique across domains. One possibility is to use the SID of the application users group in your expected domain instead of the name. Then you can check the SID of the group to make sure it matches the sid for the expected application users group at run time before checking membership. It would be much harder for a malicious user to spoof domain and group parts of the Sid then the domain and group name.
Ultimately if you are running code on a machine that is owned by the malicious user then this just raises the bar and they could still circumvent this check.

I made some example code which checks the group's SID as Mike suggested. You just need to put your group's SID in the constructor of the SecurityIdentifier class to make the check work against the currently logged on user.
Private Sub DoCheck()
Dim sid As New Security.Principal.SecurityIdentifier("S-0-0-00-0000000000-0000000000-0000000000-000"),
result As Boolean
result = IsUserInGroup(sid)
End Sub
Public Shared Function IsUserInGroup(sid As Security.Principal.SecurityIdentifier) As Boolean
Dim user As UserPrincipal
user = UserPrincipal.Current
For Each group As Principal In user.GetGroups()
If group.Sid.Equals(sid) Then Return True
Next
Return False
End Function
To make the code work you need to import System.DirectoryServices.AccountManagement:
Imports System.DirectoryServices.AccountManagement
This namespace is located in Microsoft's System.DirectoryServices.AccountManagement.dll which is available since .Net 4.0 I believe.

Related

How to enforce user validation EXCEPT on server startup in meteor?

I want no user to be able to create users with the super-admin role, I want the only super-admin created by the server upon startup. How do I create an Accounts.validateNewUser() function enforcing this?
More generally, I want all new users validated a certain way EXCEPT the one created during server startup. How do I do this?
Thank you!
When the server starts up, create the new super-admin user and make sure that this user has a unique key in its document. ex: isSuperAdmin: true. In your Accounts.validateNewUser() code (which runs on the server):
if ( Meteor.user().isSuperAdmin || Meteor.users.find().count() <= 1 ) return true; // only allow super admin to create users with exception for very first user
else throw new Meteor.error(403,'Forbidden');
You'll also need a deny rule for any attempt to set the isSuperAdmin key on a user.

Change user password in child system remotely from CUA

I am trying to find a solution which will allow me to change a user's password from our Central User Administration (CUA) system where the user's access and password is on the child system.
I tried to use BAPI_USER_CHANGE with destination call but it doest suit in my case.
(we locked change password function in child systems). This is my code with destination call
CALL FUNCTION 'BAPI_USER_CHANGE'
DESTINATION 'CLNT_500'
EXPORTING
username = p_bname
password = wa_password
passwordx = wa_passwordx
TABLES
return = it_return.
Any suggestions welcome.
We tried to do something similar a while ago, and we ended up doing it in two steps:
BAPI_USER_CHANGE sets an initial password for the user
SUSR_USER_CHANGE_PASSWORD_RFC sets a productive password. It needs the old password as a parameter, that's why we needed to call BAPI_USER_CHANGE first.

Which parameter is used for authentication in LDAP

In case of LDAP authenticaion, what are the parameters that are generally used for authentication. I guess using DN would be a headache for users logging in via ldap because it is too large to remember.
How is the option of using uid or sAMAccountName for authentication where in my implementation, I retrieve the dn of the corresponding uid or sAMAccountName and proceed to authentication.
Am I going the right track?
In LDAP, a connection or session can be authenticated. When an LDAP client makes a new connection to an LDAP directory server, the connection has an authorization state of anonymous. The LDAP client can request that the authorization state be changed by using the BIND request.
A BIND request has two forms: simple and SASL. Simple uses a distinguished name and a password, SASL uses one of a choice of mechanisms, for example, PLAIN, LOGIN, CRAM-MD5, DIGEST-MD5, GSSAPI, and EXTERNAL - all of which except for GSSAPI and EXTERNAL are too weak to use in production scenarios or mission-critical areas.
To Use the simple BIND, construct a BIND request and transmit it to the LDAP directory server. The LDAP directory server will respond with a BIND response in which is contained a result code. The result code is an integer, anything other zero indicates that the BIND request failed. If the result code is zero, the BIND request succeeded and the session authorization state has been changed to that of the distinguished name used in the BIND request.
Each subsequent BIND request on the same connection/session causes the authorization state to be set to anonymous and each successive successful BIND request on the same connection/session causes the authorization state to be set to the authorization state associated with the authentication ID, which is the distinguished name in the case of the simple BIND, but might be something else entirely where SASL is used - modern professional quality servers can map the incoming names to different DNs.
Whichever language is used, construct a BIND request, transmit it to the server, and interpret the response.
Update:
If the distinguished name is not known, or is too cumbersome (often the case with web application users who don't know how they are authenticated and would not care if they did know), the LDAP application should search the directory for the user. A successful search response always contains the distinguished name, which is then used in a simple BIND.
The search contains at a minimum, the following:
base object: a distinguished name superior to the user, for example, dc=example,dc=com
a scope: base level, one level below base, or subtree below base. For example, if users are located subordinate to ou=people,dc=example,dc=com, use base object ou=people,dc=example,dc=com and a scope of one-level. These search parameters find entries like: uid=user1,ou=people,dc=example,dc=com
a filter: narrows down the possible search results returned to the client, for example (objectClass=inetOrgPerson)
a list of requested attributes: the attributes from an entry to return to the client. In this case, use 1.1, which means no attributes and returns on the DN (distinguished name), which is all that is required for the simple BIND.
see also
the links in the about section here
LDAP servers only understand LDAP queries; they don't have "usernames" like you and I are used to.
For LDAP, to authenticate someone, you need to send a distinguished name of that person's (or entity's) entry in LDAP; along with their password.
Since you mentioned sAMAccountName I am assuming you are working with Active Directory. Active Directory allows anonymous binds - this means you can connect to it without providing any credentials; but cannot do any lookups without providing credentials.
If you are using python-ldap and Cython (and not IronPython which has access to the various .NET APIs that make this process very easy); then you follow these steps.
Typically you use a pre-set user that has appropriate rights to the tree, and connect to the directory with that user first, and then use that user's access for the rest of the authentication process; which generally goes like this:
Connect to AD with the pre-set user.
Query active directory with the pre-set user's credentials and search for the distinguished name based on the sAMAccountName that the user will enter as their "username" in your form.
Attempt to connect again to Active Directory using the distinguished name from step 2, and the password that the user entered in their form.
If this connection is successful, then the user is authenticated.
So you need two main things:
The login attribute (this is the "username" that LDAP understands)
A LDAP query that fetches information for your users
Following is some rough code that can do this for you:
AD_USER = 'your super user'
AD_PASSWORD = 'your super user password'
AD_BIND_ATTR = 'userPrincipalName' # this is the "login" for AD
AD_URL = "ldap://your-ad-server"
AD_DN = "DC=DOMAIN,DC=COM"
AD_LOGIN_ATTR = 'sAMAccountName' # this is what you user will enter in the form
# as their "login" name,
# this is what they use to login to Windows
# A listing of attributes you want to fetch for the user
AD_ATTR_SEARCH = ['cn',
'userPrincipalName',
'distinguishedName',
'mail',
'telephoneNumber','sAMAccountName']
def _getbinduser(user):
""" This method returns the bind user string for the user"""
user_dn = AD_DN
login_attr = '(%s=%s)' % (AD_LOGIN_ATTR,user)
attr_search = AD_ATTR_SEARCH
conn = ldap.initialize(AD_URL)
conn.set_option(ldap.OPT_REFERRALS,0)
conn.set_option(ldap.OPT_PROTOCOL_VERSION,3)
try:
conn.bind(AD_USER,AD_PASSWORD)
conn.result()
except:
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
# Exit the script and print an error telling what happened.
sys.exit("LDAP Error (Bind Super User)\n ->%s" % exceptionValue)
try:
result = conn.search_s(user_dn,
ldap.SCOPE_SUBTREE,
login_attr, attr_search)
except:
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
# Exit the script and print an error telling what happened.
sys.exit("LDAP Error (Search)\n ->%s" % exceptionValue)
# Return the user's entry from AD, which includes
# their 'distinguished name'
# we use this to authenticate the credentials the
# user has entered in the form
return result[0][1]
def authenticate(user,password):
bind_attr = AD_BIND_ATTR
user_dn = AD_DN
login_attr = '(%s=%s)' % (AD_LOGIN_ATTR,user)
data = _getbinduser(user)
if len(data) == 1:
return None
# Information we want to return from the directory
# for each user, season to taste.
info = {}
info['name'] = data['cn'][0]
info['email'] = data['mail'][0]
try:
info['phone'] = data['telephoneNumber'][0]
except KeyError:
info['phone'] = 'Not Available'
conn = ldap.initialize(Config.AD_URL)
conn.set_option(ldap.OPT_REFERRALS,0)
conn.set_option(ldap.OPT_PROTOCOL_VERSION,3)
try:
# Now we have the "bind attribute" (LDAP username) for our user
# we try and connect to see if LDAP will authenticate
conn.bind(data[bind_attr][0],password)
conn.search(user_dn,ldap.SCOPE_SUBTREE,login_attr,None)
conn.result()
return info
except (ldap.INVALID_CREDENTIALS,ldap.OPERATIONS_ERROR):
return None
One small expansion on Terry's excellent comment. If you store all your users in the same part of the DIT, and use the same attribute to identify them, you can programmatically construct the DN, rather than searching for it.

2 DKIM on same domain

We are using an external service for our newsletter, which has required the followin DKIM setup in our domain gipote.dk:
_domainkey.gipote.dk. 43200 IN TXT "o=~"
default._domainkey.gipote.dk. 43200 IN TXT "k=rsa\; p=MIGf...ibnrkoqQIDAQAB"
(I truncated the public key for purpose of readability...)
However we are also sending out e-mail from our own server, which I would also like to sign.
Is it possible to have more than one public-key TXT record in our domain gipote.dk? If so, how should it be set up?
EDIT: I do not have access to the private key, that is used by the newsletter service. So I will not be able to just install that on my own server.
/ Carsten
I found out, that the answer is YES :-)
"default" can easily be replaced with another selector name.
Yes you can change the default to another selector.
BUT if you do the domain it is on will no longer verify the domain.
You need to Add a second key NOT CHANGE whats existing
using Google mail you end up with
default._domainkey "v=DKIM1; k=rsa; p=MIIBIj....."
google._domainkey "v=DKIM1; k=rsa; p=MIGfMA......"

Adding custom roles - VB 2008 Winforms

I have a winforms (VB 2008) based app that I'm developing and I want to use custom roles for user access.
Application Layout:
I have a Main form that opens a login form when certain actions occur. The Login form intern uses an authentication class that I've created, to authenticate users and set access rights. On my Applications settings page, I have Authentication Mode set to Application-defined because I cannot use Windows Authentication in the environment where this will be deployed.
The application uses a MS SQL 2005 db and the 3 tables I'm using in the authentication process are the User_Account , User_Roles and User_Access tables. The combination of an account in the User_Account and the roles within the User_Roles table are the bases for the User_Access table. Using the User_Access table is how I assign access to the various functions within the application
Authentication Method:
To authenticate a user, I'm using the "My.User.CurrentPrincipal" (Code below) method. The My.User object works great and allows the use of "My.User.Name" property throughout the app when referring to the currently authenticated user.
Access Method:
In order to set the current users access levels I'm using a function within my Authentication class and passing in My.User.Name as a variable. The function uses a Dataset Table Adaptor and a Select Case statement inside a For loop to assign all the access levels for the user (Function code below).
My Problem:
This method of assigning access rights to a user does work but it's not persistent throughout the application as the My.User object is. I would like to find a way to create custom roles through the My.User object using its .IsInRole property. I would like to have these roles dynamically created using my User_Roles table.
This would allow the custom roles to be used throughout my application using the My.User.IsInRole("MyRole") syntax ...similar to how I'm currently able to use My.User.Name. Unfortunately the only roles I can currently validate against are the built in Windows type accounts (Adminisrator ...ect.).
I have found lots of information and examples related to ASP.Net as well as setting up Winforms Windows authentication but nothing so far directly related to my issue.
I think there's a way to accomplish this...but I have not been able to find it. Any help would be greatly appreciated!!
Thank you for your help!
'User Authentication example:
If Authenticate.CheckPassword(tbxUserName.Text, strPassword) Then
My.User.CurrentPrincipal = New GenericPrincipal(New GenericIdentity(tbxUserName.Text), Nothing)
'Access assignment example:
Public Shared Function GetUser(ByVal strUsername As String) As Authenticate
Using UserAdapter As New dbUserTableAdapters.User_AccountsTableAdapter()
Dim UserTable As dbUser.User_AccountsDataTable = UserAdapter.GetByUser(strUsername)
Dim tempUser As New Authenticate() _
With {.ID = UserTable(0).id, _
.Username = UserTable(0).User_Name, _
.Password = UserTable(0).id}
Using AccessAdapter As New dbUserTableAdapters.User_AccessTableAdapter()
Dim AccessTable As dbUser.User_AccessDataTable = AccessAdapter.GetByUser(tempUser.ID)
For c As Integer = 0 To AccessTable.Rows.Count - 1
Select Case AccessTable(c).Role_Id
Case RoleType.SysAdmin
tempUser.AllowSysAdmin = True
Case RoleType.Maintenance
tempUser.AllowMaintenance = True
Case RoleType.ReportAll
tempUser.AllowRptAll = True
Case RoleType.ReportException
tempUser.AllowRptExceptions = True
Case RoleType.EventManagment
tempUser.AllowEventStart = True
Case Else
End Select
Next
Return tempUser
End Using
End Using
End Function
I think you need to implement a custom IPrincipal object which accesses your SQL table. Try this page.
Edit:
First, have a look at the definitions of IIdentity and IPrincipal. You'll note that IIdentity doesn't have a 'Role' property defined. They've chosen to implement an additional property called Role on their implementation of IIdentity (SampleIIdentity) and then they've used it from their implementation of IPrincipal. What I'm suggesting is that you implement your own Role property (which queries your existing table) and returns one (or an array) of a Role type you define yourself. Then in your implementation of IPrincipal, you can code IsInRole to query the new Role property. Hopefully that makes more sense that my rather skimpy answer.