Is it possible to somehow cast or convert a WindowsIdentity type to PSCredential type? - powershell

Context: working in PowerShell, need PSCredential object, have an object of WindowsIdentity type.
Say you obtain WindowsIdentity type using:
"[Security.Principal.WindowsIdentity]::GetCurrent()"
You need PSCredential object to make a network call, e.g., Invoke-RestMethod.
Instead of calling the usual Get-Credential and prompting the user for username and pw, can we actually use the current security context to create a credential object? e.g, can we cast the WindowsIdentity object into the PSCredential (if not directly - then through a sequence of steps?).
If not then any other ideas about creating a PSCredential object from current security context (without specifying username or password - or storing encrypted username and pw as that would also require updating as the passwords change)?
Similar questions have probably been asked before but I could not find an approach of trying to convert WindowsIdentity into PSCredential type - or any definitive answer on why this might be prevented by design. If this is not fundamentally possible - what might be the reason for not supporting it? Do you see any plausible workaround?
(I tried to add a tag: PSCredential but this tag does not already exist and I do not have enough reputation to create it: I would like to add that tag: perhaps someone from the community can add it. Thanks)

I am sure others will have their take on this, but here are a few things as I understand them that would make this a real challenge and not prudent as a operational deal.
[Security.Principal.WindowsIdentity]::GetCurrent(), gives you information about your authenticated identity on the network. It does not contain any info about the user password
(https://msdn.microsoft.com/en-us/library/system.security.principal.windowsidentity(v=vs.110).aspx),
which is needed by System.Management.Automation.PSCredential
(https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscredential?view=powershellsdk-1.1.0).
Remember, the goal of GetNetworkCredential
(https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscredential.getnetworkcredential?view=powershellsdk-1.1.0#System_Management_Automation_PSCredential_GetNetworkCredential)
(which of course is a method System.Management.Automation.PSCredential), is to breakdown your user name into separate Domain and UserName strings and hands you the credential password in clear text.
For network, client access, PSCredential will not work without a valid password being provided. Of course, if you personally entered the information, you and only you can reverse it, not some remote person or service.
Think about it for a moment. Can you imagine the risk ramifications of being able to do this unabated?
Being able to just pull, dynamically, all the auth entropy of the current logged on user. This would be an instant ESP (impersonation / escalation of privilege) problem. Password obfuscation, length, complexity, with an approach like this would be meaningless. Think Pth (Pass the Hash -like attacks) situations without ever needing toe grab the hash.
Imagine, firing off a remote session to any remote host (regardless of who is logged on to it), leveraging what you state here, thus impersonating (with all their rights and privileges) the user to do very nefarious things or even just mean things (changing their passwords, desktop settings, ADDS attributes, say if they are allowed to change there Picture, phone number, maiden name, etc. all being recorded in the audit logs as if that user did it). You could log into their personal human resource files, passing the cred object to the HR website, etc. I am sure that is not your intent (at least I hope not), but still.
All that being said, if you are after user impersonation, then there are resources that present approaches on how to do this. Yet, as you look at the code to do it, it's more involved than just what you are asking for in the MS PowerShell Gallery, but even it expects you to pass it a real cred object not a WI object.
Reaching out across a network requires a full identity, user and password. Every time to try and touch a resource you have not yet touched, or who has not in a long while, you KDC (domain controller) will be engaged and without full creds the KDC Kerb TGT will fail.
Update
shivesh suman
As for ---
Thanks. Regarding: "Yet, as you look at the code to do it, it's more
involved than just what you are asking for ..." - Would it be
possible for you to point me to some of the code that you are
referring to in your comment?
Here is the code I was referring to.
Impersonate a User
New-ImpersonateUser uses the LogonUser method from the advapi32.dll to
get a token that can then be used to call the
WindowsIdentity.Impersonate method in order to impersonate another
user without logging off from the current session. You can pass it
either a PSCredential or each field separately. Once impersonation is
done, it is highly recommended that Remove-ImpersonateUser (a function
added to the global scope at runtime) be called to revert back to the
original user.
https://gallery.technet.microsoft.com/scriptcenter/Impersonate-a-User-9bfeff82

Related

Create Teams meeting by Microsoft Graph or other means

I'd like to create MS Teams meetings from another application.
The Teams application is running on the computer, outlook is not used though.
How would I accomplish this the best / easiest way without (much) user interaction?
As far as I can see, the best option would be to use the REST API to create a meeting using the api-URL https://graph.microsoft.com/v1.0/me/events.
If I can also create a meeting commandline or by COM objects or something else, I could do that, too.
So here would be what I did for research with graph so far:
I can log on to https://developer.microsoft.com/en-us/graph/graph-explorer and use my user to create meetings and get the response. To do that, I modified the permission to read / read-write the calendar. If I copy the access token and use it with a powershell Invoke-RestMethod, it also does what I want. I can do the same with Connect-Graph -Scopes "Calendars.ReadWrite". But it would show this big browser windows about the login as X.
I read about apps, but if I use the apps ID and so on to log in silently, it seems like I am not in the current user scope but in a process scope and that's different. At least I set the API permissions up to also have access to Calendars.ReadWrite via Microsoft Graph, but I get an Access denied error if I try to run the same New-MgUserEvent to create a meeting for the current user (that is running the local powershell).
If use the token with Connect-MgGraph, it displays the client and tenantID and the ContextScope is process, not current user, so that would fit.
If I understand it correctly, I could use the token to get another one for a user... (reference is this: https://learn.microsoft.com/en-us/graph/auth-v2-user )
If I use the Connect-Graph -ForceRefresh parameter (which I guess would do the same, the popup tells me I'm logged in as the current user (not process).
This is a bit odd, so before I try to use the rest api and fumble a bit around:
Can I use the example from the link to refresh the token to get a user token that has the rights that I defined (and be able to access the calendar)?
Or is there some misunderstanding on my part?
Would it be a better idea to just use something like powershell, have the user log in once per day and leave the process in the background and create the new entries from there?
Do you have to refresh a token when you use connect-graph? Or could that be done better by Rest web api, if I can export the token?
The idea of having an app that would have access to all calendars would seem like a bigger security risk and I'd kind of want to avoid that. If I could configure the apps to have access to only one specific calendar, that would be cool, too. But I did not find it when looking around.
Thanks and best regards to all that took their time to read and consider to help.

Keycloak 15.0.2 - UserFederation and AccessToken mismatch on first run

As the title says, I'm developing a Custom User Storage Provider (here forth SPI) with Keycloak 15.0.2.
I’m having trouble sorting an issue where the very first access token that is issued, does not match the expected format (is missing some fields) but also seems to be issued for a different user, if I am to judge only based on the sub field of the AccessToken generated.
To ease reproduction of the issue, you can find my repository on Github here with a complete sample FE and BE along with the keycloak configuration. I also included samples of the result tokens, jwt.io links and logs on LOGS.md file on the repo.
I think I understand why this mismatch is happening, though.
Due to the fact that I start with an empty collection of users on keycloak, I need to create the users on their first login. All I have to start with is their email address which is input on the login screen.
With this information, I setup a “temporary” Federated User until I get the user data from the “real” IDP on the isValid method (where the user actually logs-in into the third party IDP) and then get his details, which are then used to fill a more complete FederatedUser profile and store it on the userLocalStorage.
It's basically this logic (it's all also explained in comments in the repo's code):
Create an adapter/model based solely on the email from the login form to be used temporarily.
Proceed with normal operation.
Then on the isValid() method:
login the user through the REST call to the backend and get the JSESSION token
on a separate call, call the Current-User REST endpoint to get user details and map them to a Dto object
create a new adapter, based on the Dto object (which already contains all the user details like name, phoneNumber, etc) and from that, add to storage as a ksession.userLocalStorage().addUser() user and enrich with custom attributes (to later be mapped into the AccessToken)
when (and if) added, clean cache with ksession.userCache().clear()
Proceed with normal operation
However, I think that the ID/model of that first temporary user is the one that is actually being used during the issuance of the first AccessToken that is generated and is being cached somehow on some other class which then generates the AccessToken with missing information/not the correct user model.
When I reload the page (forcing it to go through the login flow again), I then get the correct AccessToken with all the fields I expected the first one to have. I also noticed that the sub of the tokens are different, and this is what leads me to this conclusion.
Does this flow/conclusion seem correct to you?
And more importantly, how can I fix this?
I have no way of getting all the user data at first or a way to import it (ideally, I didn’t even wanted to Federate, just some ReadOnly data would have been enough if I could modify the AbstractUserAdapter attributes).
Can I somehow access the CredentialInput outside the isValid method?
That’s the only way I’d have to grab all the user data since the beginning.
I’d really appreciate any help you could spare. The reproduction code is just a clone/docker up away and will replicate the issue perfectly.
Please help me figure out how to make sure the token get properly set/issued the first time around
Thanks

Why does libgit2 expose GIT_CREDENTIAL_DEFAULT as a credential type to the credential callback?

I've got a naive question about GIT_CREDENTIAL_DEFAULT. Why is it exposed to the credential callback that the clients have to implement? Can the transports not just handle this for the caller?
A server response is giving me both GIT_HTTP_AUTH_NEGOTIATE and GIT_HTTP_AUTH_NTLM, so the allowed credential types of GIT_CREDENTIAL_DEFAULT and GIT_CREDENTIAL_USERPASS_PLAINTEXT are sent to the callback. Unfortunately I check for GIT_CREDENTIAL_USERPASS_PLAINTEXT ahead of GIT_CREDENTIAL_DEFAULT. Should I just always be checking if GIT_CREDENTIAL_DEFAULT is an allowed type first and trying that before other credential types?
Should I just always be checking if GIT_CREDENTIAL_DEFAULT is an allowed type first and trying that before other credential types?
Probably? This really depends on the user experience that you want to support, but I think that this is what most users would expect.
If you were in a kerberized environment, then as a user, you would probably just expect single-signon to happen.
You will probably need to keep some state here, however, in case you supply GIT_CREDENTIAL_DEFAULT in your callback and then the authentication fails. In this scenario, you may want to try GIT_CREDENTIAL_DEFAULT first and then prompt for username/password if that fails. (Instead of getting caught in an infinite loop just blindly trying GIT_CREDENTIAL_DEFAULT in your callback. You can use the the payload on the options structure to hold this state.)
Why is it exposed to the credential callback that the clients have to implement? Can the transports not just handle this for the caller?
This is a bit of a philosophical question.
The thinking of libgit2 here is that we should not decide how to authenticate for you, the application. You can imagine that a Git GUI might try to connect to a server and then pop up a dialog that asks you how to authenticate. Maybe you want to select the currently logged in user or override that with a custom username/password.
If you didn't want to support single sign-on then either we would need to give you an option that says you don't want it, or we need to give you the data in a credential callback so that you can choose to act on it. This is a judgement call, admittedly, but the latter seemed more in keeping with the way the library tends to work.

How is one supposed to practically use the Access Control features in the Realm Mobile Platform?

I don't see an easy way to grant permissions to another user. It seems to be quite convoluted at the moment, and I wonder if I'm missing something obvious.
Say I want to invite another user to share a Realm. First I would have to ask the other user for their identification, then I would create the permission object, and then finally I would give the other user the address of my realm.
It would be great if I could share some sort of permission token via text message and let the new user register themselves. I suppose I could do that if I created another "User" which represented the shared group, and merely share this abstract user's credentials. It feels a bit hacky that way, but it seems easier to do.
I was hoping the demo application of the shared drawing environment would hold a clue, but after looking at the source code, it turns out both devices are logged in as the same user.
Am I missing something? Given the demo Draw application, how would one user practically invite a second user to join in their shared drawing environment? It seems like there would have to be a whole set of convoluted permissions and url/identification sharing handshakes.
Thanks for asking the question! Today, you will need to create a shared Realm that all users would input their user IDs into and have access to. This way any user can look up an ID and share access to another Realm.
We realize the limitations and are working on offering a number of improvements. The first is pretty close to what you describe, called a PermissionOffer object where you can inform the Realm Object Server you want to grant access to another user for a given Realm(s). The server will then provide a token you can share via any means with the other user. That user can then use the token to create a PermissionOfferResponse object and accept the access grant. This is coming soon, so stay tuned!
Later, we plan to offer a way to lookup user IDs so you don't have to replicate all of them in a shared Realm (see this issue).

How to programatically add mapped network passwords (WinXP)?

In WinXP (SP2) you can store mapped network passwords...
Start->Control Panel->User Accounts->Pick one then choose "Manage my network passwords" from Related Tasks.
I normally have about 25-30 servers mapped this way to a few different accounts/domains. The problem is that at some point during our policy updates they get wiped out and it's a real PITA to add them all back again.
Does anyone know how to add them programatically using some sort of script?
Just to clarify, the end goal is not to map drives, it's to actually create the entries in that section. This allows us to use Windows authentication for connecting to our servers (via Dameware, SSMS etc.).
Addendum:
Mark's CredWrite tip led me here...
pinvoke.net -- CredWrite (advapi32)
Which in turn led me here...
Peer Channel Blog -- Application Password Security
Both have proved very helpful.
cmdkey.exe is the CLI version of the tool - but I believe it's only included on Win2003+. I'd suspect a copy to XP would work - but may violate your EULA.
net use also has a savecred option, if you're mapping drives
According to this fairly detailed info, the CredMgr stores it's database in 2 locations. It may be enough to just back up these files:
%APPDATA%\Microsoft\Credentials\%UserSID%\Credentials
%USERPROFILE%\Local Settings\Application Data\Microsoft\Credentials\%UserSID%\Credentials
There's an API to read the credentials, CredEnumerate - but no immediate obvious way to add your own. A couple of candidates:
CredWrite takes a normal CREDENTIAL, but nothing to indicate storing past the current session.
CredUIStoreSSOCredW takes a bPersist parameter - but specifies a "realm" instead of a server or network location.
Edit: D'oh. I missed the PERSIST member of CREDENTIAL. It can be one of the following values:
CRED_PERSIST_SESSION:
The credential persists for the life of the logon session. It will not be visible to other logon sessions of this same user. It will not exist after this user logs off and back on.
CRED_PERSIST_LOCAL_MACHINE:
The credential persists for all subsequent logon sessions on this same computer. It is visible to other logon sessions of this same user on this same computer and not visible to logon sessions for this user on other computers. (This is what's stored into the Local Settings file)
CRED_PERSIST_ENTERPRISE:
The credential persists for all subsequent logon sessions on this same computer. It is visible to other logon sessions of this same user on this same computer and to logon sessions for this user on other computers.
This option can be implemented as locally persisted credential if the administrator or user configures the user account to not have roam-able state. For instance, if the user has no roaming profile, the credential will only persist locally. (This is what's stored into AppData)
It looks like CredWrite is the API you want.
NET USE(command) and WshNetwork.MapNetworkDrive(windows scripting host) are two common ways of scripting the mapping of network drives, both allow you to specify user and password.
I don't know how this would work/not work with stored passwords as you said other than knowing that if you leave the user option blank it will attempt to use the credentials of the current user.