Get user's AD role without using Remote Server Administration Tools - powershell

I'm trying to write a powershell command that checks to see if a user is part of an AD Group, however, I don't want to use the RSAT modules, as this may end up being a logon script (and we don't want users having those modules installed). This did lead me to this question, Search AD with PowerShell without using AD module (RSAT), however, I can't figure out how to filter the results check it the value is in there.
For example, the below does return a list of users, in LDAP form, for the group IT, but how do I then check a specific user (with their Username, not display name) is in there?
([System.DirectoryServices.DirectorySearcher]"(&(objectCategory=group)(name=IT))").FindOne().Properties["Member"]
FindOne() despite what it says as well, returns multiple rows; in fact FindAll() and FindOne() both return the same results.
Should I be using a different command to search AD? Specifically I want to either check an AD group contains a user (the current user), or the inverse, check a user (the current user) is a member of a particular AD group.

You can do it that way if you really need to (and I can help you do it that way if you really need) but if you are going to be running this script under the credentials of the user you are interested in, then you can get all the groups from the user's login token. That already contains a recursive list of all security groups that the user is in. (It won't include groups where the 'Group type' is "Distribution")
The login token contains a list of SIDs, so the absolute fastest way is to compare using the SID of the group you are interested in, since it won't have to make any network request at all. That's especially convenient for laptop users who may not be online when they login - your script would still work.
$currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
if ($currentIdentity.Groups.Where({$_.Value -eq "S-1-1-0"}, "First")) { #Is in "Everyone"?
"Yes"
} else {
"No"
}
To find the SID of a group, use this:
(Get-ADGroup "GroupName").SID.Value
Then copy/paste that value into the script.
If you would prefer to use the name of the group in the script, then you can convert it to a WindowsPrincipal and use IsInRole. However, this will need to make a network request to find the group by its name.
$currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
$currentPrincipal = New-Object System.Security.Principal.WindowsPrincipal($currentIdentity)
if ($currentPrincipal.IsInRole("Everyone")) {
"Yes"
} else {
"No"
}

Related

Get Website Permission with Powershell

I am trying to figure out how to get the well known Website Permission Lists with Powershell. I tried several methods. The best solution seems to me to try something like $spWeb.RoleAssignments but this delivers me not only the users and groups with ist permissions on the spweb. I also get the roleassignments from the unique lists and libraries on the website.
Do you have suggestions how can I filter to check if a user has, for example, read permission on the spweb (without regarding the lists and subwebs)?
My target is to check the spweb and ist subwebs and unique lists and libraries step by step for a user(group) like "NT AUTHORITY\Authenticated Users". Then I want to remove the roleassignment and add a new roleassignment with a group of my colleagues, so that not everybody can see the content. The uniqe permission structure should remain.
You could check if a user has specific permission level using SPWeb.DoesUserHavePermissions method:
public bool DoesUserHavePermissions(
string login,
SPBasePermissions permissionMask
)
SPWeb.DoesUserHavePermissions method (String, SPBasePermissions)
using (SPSite site = new SPSite("http://sp/"))
{
using (SPWeb web = site.OpenWeb())
{
// Make sure the current user can enumerate permissions.
if (web.DoesUserHavePermissions(SPBasePermissions.EnumeratePermissions))
{
// Specify the permission to check.
SPBasePermissions permissionToCheck = SPBasePermissions.ViewListItems;
Console.WriteLine("The following users have {0} permission:", permissionToCheck);
// Check the permissions of users who are explicitly assigned permissions.
SPUserCollection users = web.Users;
foreach (SPUser user in users)
{
string login = user.LoginName;
if (web.DoesUserHavePermissions(login, permissionToCheck))
{
Console.WriteLine(login);
}
}
}
}
}
Console.ReadLine();

Get basic information from user selected certificate in PowerShell

I'm working on a small work order app with a database back end for our Help Desk. Part of it is tracking some basic information about my organization's laptops (Manufacturer, Model, Serial Number, who it's assigned to, etc). I would use a real programming language like C# or Java, but for reasons dictated by people over my head, I'm stuck with using what is available built into Windows 10 Enterprise, so PowerShell with WPF.
Our network has a Windows domain with a large Active Directory forest and smart card authentication. What I would like to do, if possible, is have the user select their smart card certificate (the user using this app will be different than the user who logged into Windows i.e. there will be multiple smart cards inserted) with a UAC prompt or Get-Credential prompt. Entering their pin is not a requirement, though it would be nice to confirm their identity. All I want is to retrieve some basic information from the certificate/card they select, such as display name and email address. I'll be using the email address to query my database for other information such as which laptop(s) they're assigned. I would like to avoid doing an Active Directory lookup if possible, but that option is not completely off the table.
Below are a few things I have found but they all are sort of partial solutions to what I'm trying to do and I'm not sure how to put it all together. Get-Credential prompts the user to pick a smart card and enter their pin, which does what I'm looking for up front, but in the back it returns a PSCredential object that contains a username (coded somehow, but I can't find which encoding is used, or maybe it's a UID) and SecureString password (not validated, the user can leave this blank or enter anything). I don't know what to do with this to get the information I want. Get-ADUser doesn't seem to be able to return a user object using a PSCredential object as identity. Is there something I am missing or not understanding about this? Is what I'm trying to do possible?
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/get-credential?view=powershell-5.1
View All Certificates On Smart Card
https://www.akaplan.com/blog/2013/10/get-users-mailaddress-from-smartcard-with-powershell/
https://blogs.msdn.microsoft.com/alejacma/2010/12/15/how-to-enumerate-all-certificates-on-a-smart-card-powershell/
This last link seems like it would work but I'm not sure how to put it into use. The documentation is very sparse.
If I wanted to work with certificates based on the smart cards inserted at the time I would use certutil.exe to pull all of the smart card info. Then grab the certificate serial numbers from the resultant text and query the CurrentUser\MY certificate store matching the serial numbers. Once I had the certificates I would pass that info to Out-GridView with the -OutputMode Single parameter to allow the user to select a certificate. From there you have the user's info based on the certificate shown.
$SCSerials = certutil -scinfo -silent | Where{$_ -match 'Serial Number: (\S+)'} | ForEach {$Matches[1]}
$SelectedThumb = Get-ChildItem Cert:\CurrentUser\my | Where{$_.SerialNumber -in $SCSerials} | Select Subject,Issuer,NotBefore,NotAfter,Thumbprint | Out-GridView -Title 'Select a smartcard certificate.' -OutputMode Single |% Thumbprint
$UserCert = Get-Item Cert:\CurrentUser\My\$SelectedThumb
Then $UserCert.Subject is the distinguished name of the user and you can use that to query AD or whatever you want.

Testing stateful Mojolicious apps

I want to test hiding and unhiding of an entry. I conduct the following tests in Mojolicious t/basic.t:
my $t = Test::Mojo->new('AdminApi');
$t->get_ok('/publications/hide/1');
$t->get_ok('/read/publications/meta')->content_unlike(qr/Paper with id 1:/i);
$t->get_ok('/read/publications/meta/1')->content_like(qr/Cannot find entry id: 1/i);
$t->get_ok('/publications/unhide/1');
$t->get_ok('/read/publications/meta')->content_like(qr/Paper with id 1: <a href/i);
$t->get_ok('/read/publications/meta/1')->content_unlike(qr/Cannot find entry id: 1/i);
My problem is that the two lines '/publications/hide/1' and '/publications/unhide/1' do not hide and unhide the entry. The state of the entry remains untouched.
If I repeat the steps manually in the browser everything works well. For the obvious reasons I want to have it automated with the tests. How to do this?
EDIT: The calls '/publications/hide/1' and '/publications/unhide/1' change the state of the database - just a simple UPDATE query. The change applies to the whole application - for all users. But one needs to be logged in as a user to hide/unhide. Question: how do I emulate a logged user during the test?
Contents generated by '/read/publications/meta' and '/read/publications/meta/1' can be read without login.
Bitbucket Repo
File with test code: basic.t
As you have already said, you need to be logged in to perform the hide and unhide action.
my $t = Test::Mojo->new('AdminApi');
You are creating a new UserAgent here. The Test::Mojo class inherits from Mojo::UserAgent. It has a cookie_jar and thus keeps a session alive. You need that to perform this action:
$t->get_ok('/publications/hide/1');
But right now you are not logged in. What you need to do is log in the user. Looking at the code in your repository, you actually assert that you are not logged in.
$t->get_ok('/')->status_is(200)->content_like(qr/Please login or register/i);
Before you perform the hide, you need to log in the user. After digging a bit in your code I found the action and the template to do that, so I know what the request needs to look like.
$t->post_ok(
'/do_login' => { Accept => '*/*' },
form => { user => 'admin', pass => 'hunter2' }
);
Now your $t UserAgent should be logged in and you can do the hide. Note that get_ok only checks if there was no transport error. So in fact it would make sense to now check if in fact you are now logged in.
You could do that by introspecting the session in the application, by checking the logfile (you are writing "Login success" there) or by checking the page for some string that says that the user is logged in. In templates/display/start.html.ep there is a text that welcomes the logged-in user, so you can use that.
$t->post_ok(
'/do_login' => { Accept => '*/*' },
form => { user => 'admin', pass => 'hunter2' }
)->text_like(qr/Nice to see you here admin/i);
Because text_like uses the text-nodes, the <em> around the username is not relevant in the test.
Right, now we know you are logged in. Time to switch the thing on and off.
$t->get_ok('/publications/hide/1');
Because there is no obvious error thrown for that as far as I can tell, I don't see how to test the success of that. Status code is one way, but there might be something in the content as well that you could test.
To verify the state of the application, you would now call the publication.
$t->get_ok('/read/publications/meta')->content_unlike(qr/Paper with id 1:/i);
$t->get_ok('/read/publications/meta/1')->content_like(qr/Cannot find entry id: 1/i);
Right. But remember, our $t is still logged in. Maybe the logged-in user is allowed to see hidden stuff as well as unhidden stuff. Maybe they are not.
It's probably safer to make a second UserAgent that's not logged in, and check with that one as well.
# check with an unauthorized user
my $t_not_logged_in = Test::Mojo->new('AdminApi');
$t_not_logged_in
->get_ok('/read/publications/meta')
->content_unlike(qr/Paper with id 1:/i);
$t_not_logged_in
->get_ok('/read/publications/meta/1')
->content_like(qr/Cannot find entry id: 1/i);
Now basically you repeat the same thing by unhiding your content and testing again. Rinse and repeat.
Keep in mind that unless you are using an explicit testing database (which you seem not to do), you cannot be sure that there even is an entry 1. Or what the name of that is. You should use fixtures for the tests. You could, for example, create a fresh instance of the DB using sqlite and work with that.

Is it possible to run a specific java method after all of the #Given statements have completed for a specific scenario?

Currently I have a story written like:
Given I login as a user
And that user likes computers
And that user has a car
When that user goes to school
Then he will be happy
I want to be able to execute a java login method after I have collected all of the Given statement data to login.
Note: the last given statement changes between stories, and the user has different variables that could be assigned to that user.
Is it possible to do something like this?
One alternative is you to use tabular parameters this way:
Given an user logs into application with:
|Id|Taste|Belongings|
|Bob|computers|car|
and this step method:
#Given("an user logs into application with: $loginInfo")
public void theTraders(ExamplesTable loginInfo) {
callLoginProcedure(loginInfo);
}
you could see more details here.

LDAP group membership filter used in RT3

I am trying to setup LDAP authentication to an Active Directory server for an RT3 site.
I think that there is an error in the LDAP authentication module, but I really do not understand what the filter is trying to do. See RT/Authen/ExternalAuth/LDAP.pm line 126:
$ldap_msg = $ldap->search( base => $group,
filter => $filter,
attrs => \#attrs,
scope => 'base');
There is a config file that specifies the group, group_attr and group_attr_value.
Group is passed as $group, and the filter is created from a group_attr=group string. In my case group_attr = present and the memberOf line comes back with CN=ITAdmins,CN=Builtin,DC=SPGLOBAL,DC=local and the filter becomes Filter: (present=CN=ITAdmins,CN=Builtin,DC=SPGLOBAL,DC=local) and Attrs: dn.
This is invalid for a filter, but can any one who knows a bit more about this see what is meant to be happening?
Thanks for posting the link to the code, that makes it much simpler to understand.
So the model is, authentitcate with username and password, then $group, if defined means check that they are a member of a group to let them in.
$group should be a full LDAP DN, so cn=AccessGroup,ou=Groups,dc=myDomain,dc=com or the like.
$group_attr_val should be member, memberOf, or maybe Member, depending on whatever the member attribute is in your target LDAP directory.
So I think your issue is that group-attr=present is probably wrong and should be as simple as member instead.