HttpContext.Current.User.Identity not populated after sign in - vb.net

So I'm using AspNet Identity and I'm trying to access the User session variable in Http.Context.Current.User after signing in. I've read online that it should be automatically populated once the sign in attempt is successful. However this doesn't seem to be the case for me.
This is my code:
Dim email As String = txtEmail.Text
Dim password As String = txtPassword.Text
Dim user As ApplicationUser
If Session("LocalNetwork") Then
Await _signInManager.PasswordSignInAsync(email, password, False, False))
Dim y = HttpContext.Current.User.Identity.GetUserId
End If
The signin is successful and I'm trying to access my UsersID but it returns null.
Web config:
<authentication mode="None" />
Anyone know why?

It's because I was checking if the user was authenticated in the same request as updating them. So they wont be authenticated until the end of the request.

Related

How to show error messages from AD with UserPrinciple.ChangePassword()?

I am trying to change a active directory user password through an application done by VB.net and the password is able to change when password policy is met but when I try to test it with a new password that does not satisfy the password policy, there is no error returned. Is there something I'm doing wrong?
I have already tried using DirectoryEntry instead and even though that does show an error from AD when password policy isn't met, it does not change the password when password policy is met. This is the segment of the code:
Try
Dim context As PrincipalContext = New PrincipalContext(ContextType.Domain, "corp.contoso.com", "OU=Students,DC=corp,DC=contoso,DC=com")
Dim userPrincipal As UserPrincipal = userPrincipal.FindByIdentity(context, IdentityType.SamAccountName, UserName)
Using userPrincipal
userPrincipal.ChangePassword(OldPassword, NewPassword)
userPrincipal.Save()
lreturnvalue = "Password successfully changed"
End Using
Catch ex As Exception
lreturnvalue = ex.InnerException.Message
End Try
Currently, I will be able to change the user's password if password policy requirements are met but no error is returned when it isn't met. Does anyone know why is this like that?

Active Directory: Add New User C# / VB

I browsed other questions and couldn't find the answer.
What is the appropriate way to add a new user to a active directory specific group when the "current user" running the application does not have access rights to add new users?
I am currently authenticating as the domain Administrator to do it, but obviously that is a security no-no and I don't want the Administrator user's credentials hard-codeded in my code.
I assume the answers is not in my code itself but that I have to create a user in the Active Directory that has privileges to add users.
So my question is a combination of a AD and a Coding question:
1) How do I create a AD user that ONLY has access rights to add users to specific OU and CN security group?
2) Is their any way possible to not hard-code the password for this user?
Or... am I going about this entirely wrong?
Here is my current VB.NET code:
Public Function CreateUser(ByVal UserName As String, ByVal Password As String, ByVal DisplayName As String) As Boolean
Try
'Dim catalog As Catalog = New Catalog()
Dim de As DirectoryEntry = New DirectoryEntry()
de.Path = "LDAP://OU=TS2xUsers,DC=dc,DC=example,DC=com"
de.AuthenticationType = AuthenticationTypes.Secure
de.Username = "Administrator"
de.Password = "foopassword"
'1. Create user accountd
Dim users As DirectoryEntries = de.Children
Dim newuser As DirectoryEntry = users.Add("CN=" & DisplayName, "user")
newuser.Properties("givenname").Value = DisplayName
newuser.Properties("name").Value = DisplayName
newuser.Properties("displayName").Value = DisplayName
newuser.Properties("SAMAccountName").Value = UserName
newuser.Properties("userPrincipalName").Value = UserName & "#dc.example.com"
'newuser.Properties("OU").Value = "TS2xUsers"
newuser.CommitChanges()
Dim ret As Object = newuser.Invoke("SetPassword", Password)
newuser.CommitChanges()
Dim exp As Integer = CInt(newuser.Properties("userAccountControl").Value)
exp = exp And Not &H2 'enable acccount
exp = exp Or &H10000 'dont expire password
newuser.Properties("userAccountControl").Value = exp
newuser.CommitChanges()
''' 5. Add user account to groups
If MakeTSUser(newuser) = False Then
Return False
newuser.Close()
de.Close()
End If
newuser.Close()
de.Close()
Return True
Catch ex As Exception
MsgBox("Failed to create user due to the following reason: " & ex.Message, MsgBoxStyle.Critical)
Return False
End Try
End Function
Private Function MakeTSUser(ByVal deUser As DirectoryEntry) As Boolean
Try
Dim deRBGroup As New DirectoryEntry
deRBGroup.Path = "LDAP://CN=TSUsers,CN=Builtin,DC=dc,DC=example,DC=com"
deRBGroup.AuthenticationType = AuthenticationTypes.Secure
deRBGroup.Username = "Administrator"
deRBGroup.Password = "foopassword"
Dim deDomainUsers As New DirectoryEntry
deDomainUsers.Path = "LDAP://CN=Domain Users,CN=Users,DC=dc,DC=example,DC=com"
deDomainUsers.AuthenticationType = AuthenticationTypes.Secure
deDomainUsers.Username = "Administrator"
deDomainUsers.Password = "foopassword"
Dim primaryGroupToken As Object = Nothing
deRBGroup.Invoke("Add", New Object() {deUser.Path.ToString()})
deRBGroup.CommitChanges()
'Get Primary Group Token of MYGROUP
deRBGroup.Invoke("GetInfoEx", New Object() {New Object() {"primaryGroupToken"}, 0})
primaryGroupToken = deRBGroup.Properties("primaryGroupToken").Value
'Assign Primary Group Token value of MYROUP to the User's PrimaryGroupID
deUser.Properties("primaryGroupID").Value = primaryGroupToken
deUser.CommitChanges()
'Remove the User from "Domain Users" group
deDomainUsers.Invoke("Remove", New Object() {deUser.Path.ToString()})
deDomainUsers.CommitChanges()
Return True
Catch ex As Exception
Return False
End Try
End Function
What is the appropriate way to add a new user to a active directory specific group when the "current user" running the application does not have access rights to add new users?
Run the app as a user that does have those permissions... but you already know this:
I assume the answers is ... to create a user in the Active Directory that has privileges to add users.
Is their any way possible to not hard-code the password for this user?
Good question. One way to do this by setting up a Windows Scheduled Task. You can setup a task to run on demand, with no actual schedule, and to run as any user you want, including your new service account. You will have to put in the password for that user when you setup the task, but only when you first setup the task, and the actual password won't be stored... only the authentication token, which is not transferable. Then your desktop application can trigger the task to start.
Another way to do this is to grant the unprivileged HR or helpdesk users who run your app permissions to create new users just within your specific OU. In the case of a web app, you can also do this for the user account that runs the web site, as long as you have appropriate logging and auditing in place.
The other option is to create a separate service to create the users, which runs as the appropriate user. This could be a web service, where less-privileged authenticated users can post the new account information, or it could be a Windows service doing something like watching a file share, where your unprivileged users then have the ability or write to the file share. Then your program can know how to call the service or write the correct file formats into the share.

.NET Google API access token failing with no refresh token specified

I am trying to set up a class that can wrap around the .NET Google API so that I can use an Access Token that I have previously obtained to access a user's Google Drive. As of right now, I am just trying to get it to work so that I do not require a Refresh Token (more on that in a second). The ultimate goal is for somebody to go through a web page I have set up to authenticate where I obtain both an Access Token and a Refresh Token by directly calling to the Google Rest API (which I store in a database). They can then request to upload/download files onto their Drive on a different page which will first obtain the appropriate information from the database and then use the .NET Google API Library when accessing Drive.
However, when I attempt to access their Drive I get the the following error:
The access token has expired and could not be refreshed. Errors: refresh error, refresh error, refresh error
I know that the Access Token is valid because I obtain it only seconds earlier during my testing. Here is my code for setting up the Drive Service:
' NOTE: Code altered for brevity
Public Sub Initialize(accessToken As String)
' Set up the client secret information based on the default constants
Dim clientSecrets As New ClientSecrets()
clientSecrets.ClientId = DEFAULT_CLIENT_ID
clientSecrets.ClientSecret = DEFAULT_CLIENT_SECRET
' Set up a token based on the token data we got
' NOTE: Is it OK to leave some strings as NULL?
Dim token As New Responses.TokenResponse()
token.AccessToken = accessToken
token.RefreshToken = ""
token.TokenType = "Bearer"
token.IssuedUtc = DateTime.Now
token.ExpiresInSeconds = 3600
token.Scope = "drive"
token.IdToken = ""
' Set up a flow for the user credential
Dim init As New GoogleAuthorizationCodeFlow.Initializer()
init.ClientSecrets = clientSecrets
init.Scopes = New String() {DriveService.Scope.Drive}
init.Clock = Google.Apis.Util.SystemClock.Default
' Set up everything else and initialize the service
Dim baseInit As New BaseClientService.Initializer()
baseInit.HttpClientInitializer = New UserCredential(New GoogleAuthorizationCodeFlow(init), "user", token)
baseInit.ApplicationName = APP_NAME
_service = New DriveService(baseInit)
End Sub
Shortly after that, I then use the following code to request a folder so I can check to see if it exists or not.
Private Function GetDriveFolder(folderPath As String, ByRef folderIds As String(), Optional createMissingFolders As Boolean = False, Optional parentFolderId As String = "root") As Data.File
Dim creatingFolderPath As Boolean = False
Dim currentFolder As Data.File = Nothing
Dim folderPathSplit As String() = folderPath.Replace("/", "\").Trim("\").Split("\")
Dim folderIdList As New List(Of String)
folderIds = {}
' Loop through each folder in the path and seek each out until we reach the end
For x As Integer = 0 To folderPathSplit.Length - 1
Dim result As FileList = Nothing
If Not creatingFolderPath Then
' Build a list request which we will use to seek out the next folder
Dim request As FilesResource.ListRequest = _service.Files.List()
request.Q = "mimeType='application/vnd.google-apps.folder' and name='" & folderPathSplit(x) & "'"
If currentFolder Is Nothing Then
request.Q &= " and '" & EscapeDriveValue(parentFolderId) & "' in parents"
Else
request.Q &= " and '" & EscapeDriveValue(currentFolder.Id) & "' in parents"
End If
request.Spaces = "drive"
request.Fields = "files(id, name)"
' Execute the search, we should only get a single item back
' NOTE: Error thrown on this request
result = request.Execute()
End If
' So on.....
So, I'm just trying to get it to work with only the Access Token for the time being because if it ends up getting refreshed I'll need to know so that I can update my database. However, if I do include the Refresh Token I get the following error:
Error:"unauthorized_client", Description:"Unauthorized", Uri:""
I'm guessing this has something to do with the way I have configured my application through the Dev Console but if I authenticate through the Google API Library by having it launch a browser to get my credentials everything works fine. So, I'm really not sure where to go from here as I haven't found anybody having similar problems and the guides don't cover specifying your own Access Token.
Also, as a quick note this is the URL I am using when having the user authenticate:
String.Format("https://accounts.google.com/o/oauth2/v2/auth?client_id={0}&state={1}&redirect_uri={2}&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&access_type=offline&include_granted_scopes=true&prompt=select_account%20consent&response_type=code", GOOGLEAPI_CLIENTID, validateState, redirectUri)
Thanks for the help!
If you have an access-token then the simplest way to create a google credential is to use the GoogleCredential.FromAccessToken() method passing in your access token.
This returns you a GoogleCredential instance which you can use to set the HttpClientInitializer property when building the DriveService.
If you then still get an error when accessing the drive service, then it's likely there's something incorrect in how you are asking for the access-token.

Get authenticated ClientContext with logged in credentials

I'm new to using SharePoint. Is it possible to get an authenticated ClientContext without a username and password? I would like to make my app automatically access SharePoint if the machine is already logged in to Office 365 (word,excel,outlook) or to SharePoint in a web browser. I need the authenticated ClientContext so i can pass the credentials to a DownloadFile method.
Private Sub DownloadFile(webUrl As String, credentials As ICredentials, fileRelativeUrl As String)
Using client = New WebClient()
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
client.Headers.Add("User-Agent: Other")
client.Credentials = credentials
client.DownloadFile(webUrl, fileRelativeUrl)
End Using
End Sub
Thanks in advance.

Is it possible to authenticate an Active Directory User with an Expired password?

I have a web form that uses AD to authenticate users. I want to be able to authenticate users with expired password, and redirect them to the password change page after authentication.
if for instance, a site admin reset a users password, I use the method below, to make the user reset their password on next logon.
Public Shared Sub ForceUserToResetPassword(ByVal LDAP_URI As String, ByVal UserName As String, ByVal Auth_UserName As String, ByVal Auth_Password As String)
Dim LDAPEntry As DirectoryEntry = Nothing
Try
LDAPEntry = New DirectoryEntry(LDAP_URI, Auth_UserName, Auth_Password, AuthenticationTypes.Secure)
Dim LDAPSearch As New DirectorySearcher()
LDAPSearch.SearchRoot = LDAPEntry
LDAPSearch.Filter = "(&(objectClass=user)(sAMAccountName=" & UserName & "))"
LDAPSearch.SearchScope = SearchScope.Subtree
Dim results As SearchResult = LDAPSearch.FindOne()
If Not (results Is Nothing) Then
LDAPEntry = New DirectoryEntry(results.Path, Auth_UserName, Auth_Password, AuthenticationTypes.Secure)
End If
LDAPAccess.SetProperty(LDAPEntry, "pwdLastSet", 0)
LDAPEntry.CommitChanges()
Catch ex As Exception
End Try
End Sub
Doing this makes the user's password expire. If the user try to logon with their new password the authentication fails with "Logon failure: unknown username or bad password".
This is my auth. method:
Public Shared Function AuthADuser(ByVal LDAP_URI As String, ByVal UserName As String, ByVal password As String, ByVal Auth_UserName As String, ByVal Auth_Password As String) As Boolean
Dim IsAuth As Boolean = False
Dim LDAPEntry As DirectoryEntry = Nothing
Try
LDAPEntry = New DirectoryEntry(LDAP_URI, UserName, password, AuthenticationTypes.Secure)
Dim tmp As [Object] = LDAPEntry.NativeObject
IsAuth = True
Catch ex As Exception
LDAPEntry.Dispose()
If ex.Message.StartsWith("The server is not operational") Then
IsAuth = False
ElseIf ex.Message.StartsWith("Logon failure:") Then
Throw New ApplicationException("The Username and password combination are not valid to enter the system.")
End If
Finally
LDAPEntry.Close()
End Try
Return IsAuth
End Function
Is there a way around this?
Thanks for your help.
In my understanding, if a user is required to Change his Password at Next Logon (User's password has expired) Active-Directory will not allow us to use LDAP to determine if his password is invalid or not. This is due to the fact that a user must change password. I found here the following solution :
To determine if password is expired, you may call Win32:LogonUser(), and check the windows error code for the following 2 constants:
ERROR_PASSWORD_MUST_CHANGE = 1907
ERROR_PASSWORD_EXPIRED = 1330
I have a non official answer. As administrator you put pwdLastSet to -1 for the user where pwdLastSet is set to 0. The effect of this is to make Active-Directory believe that the password has just been changed. Then, you check the password with your AuthADuser method. Then you put back pwdLastSet to 0. I do not test it, but just imagine it, it's not so clean on the security point of view (in France we call that "bricolage").
Just tell me if it works ?
I hope it helps;
JP