Manually checking users from a trusted domain - active-directory

How can I check a user in a trusted domain exists and after that how can I check that the same user is not enabled?

Since this was posted on SO, I will assume you want a programming solution.
Since you didn't specify a language, I will also assume that Powershell is acceptable.
Test if user exists in domain:
$netbiosdomainname = "DOMAIN"
$username = "johndoe"
try {
[adsi]::Exists("WinNT://$netbiosdomainname/$username,user")
}
catch {
... user does not exist ...
}
See this article for why this needs try/catch.
Test if user enabled:
$user = [adsi]"WinNT://$netbiosdomainname/$username,user"
if ($user.AccountDisabled) {
... account is disabled ...
}

Related

Grant a service principal access to check password expiry of other apps (or own)

I'm trying to use the least privilege approach. I know how to grant directory or app reader privilege, but that would open the whole AAD and I want to be more selective. I also figured that an owner of an app could do that, but that would also allow the principal to read and modify the passwords. Is it even possible to grant access to only read password expiry for specific app/service principal?
resource "azurerm_role_assignment" "secret_checker_monitors_app_pwd_expiry" {
role_definition_name = "Reader"
principal_id = azuread_service_principal.checker.object_id
scope = azuread_service_principal.another.object_id
}
I've tried this, but it complains about invalid scope. What would be the correct scope? I suppose some /aad/scope/.../x-y-z-object-id. What would be the correct role name? Or would I need a custom role? Which permission?
Someone tried something similar here and concluded it was not possible. Still hoping...
Use azuread_app_role_assignment instead:
resource "azuread_app_role_assignment" "secret_checker_monitors_app_pwd_expiry" {
app_role_id = azuread_service_principal.msgraph.app_role_ids["Application.Read.All"]
principal_object_id = azuread_service_principal.checker.object_id
resource_object_id = azuread_service_principal.other.object_id
}
resource "azuread_service_principal" "msgraph" {
application_id = data.azuread_application_published_app_ids.well_known.result.MicrosoftGraph
use_existing = true
}
data "azuread_application_published_app_ids" "well_known" {}
The azurerm_role_assignment is for Azure resources. azuread_app_role_assignment was introduced in azuread provider 2.4.

Drupal 7:User information not saving when edited by allowed users

I'm currently developping a new website for an artists organization. The administrator role is allowed to create accounts and some other node content, the created accounts have the same default role called "artisan". Administrators are Artisans as well. Artisans can create and edit their own content. Both administrators and artisans should be able to edit user profile (all for admin, only their own for artisan). The fact is admin can create a user but nobody (except user1) can save user profile after edit (but it works great for other nodes). Permissions have been scanned multiple times. I have been searching everywhere with no success, what am I missing ? I made very few changes, the only related code I wrote is the following :
<?php
function canardesign_system_form_alter(&$form, &$form_state, $form_id){
global $user;
switch ($form_id){
case 'oeuvre_node_form':
$form['actions']['submit']['#submit'][] = 'canardesign_system_oeuvre_redirect';
if (in_array('artisan', array_values($user->roles))){
$form['field_auteur']['#type']= 'hidden';
$form['field_auteur']['und']['#default_value']= $user->uid;
}
break;
case 'user_profile_form':
if (in_array('artisan', array_values($user->roles))){
$form['actions']['submit']['#submit'][] = 'canardesign_system_user_profile_form_submit';
}
break;
}
}
function canardesign_system_oeuvre_redirect($form, &$form_state) {
$type=$form['#node']->type;
if(isset($type))
{
$node = node_load($form_state['nid']);
$uid=field_get_items('node', $node, 'field_auteur')[0]['target_id'];
$form_state['redirect'] = 'oeuvres/'.$uid;
}
}
function canardesign_system_user_profile_form_submit($form, &$form_state) {
drupal_goto('artisans');
}
/*default role when administrator (who is artisan as well) creates an account*/
function canardesign_system_user_insert(&$edit, $account, $category) {
global $user;
if (in_array('artisan', array_values($user->roles))){
$account->role = 'artisan';
}
}
?>
Thank you for your help.
I'm not sure if this is the cause of your issue, but calling drupal_goto() inside a submit hook is definitely problematic. It essentially shorts out the handling of the form.
This may be causing the issue by preventing other necessary code from executing.
You should instead set the redirect key of $form_state to the destination you would like the user to end up on.
Once the form handling is complete, Drupal will send the user there.
function canardesign_system_user_profile_form_submit($form, &$form_state) {
$form_state['redirect'] = 'artisans';
}

Phpunit password comparison

I would like to test a login function that one of the developers produced. What I would like to do is have test-users be created in my setUp and then I would like to use these users to test the login function. I would like to see that it returns the correct boolean when username and password are equal to the ones stored in our database. My problem is that when I am inserting my users at the moment I am giving the passwords in plain-text hence they are being stored in the database in plain-text, however there is an issue here. The login function hashes the password as you are trying to log in as the passwords in the database are hashed when registration is done. So basically the plain-text password I just inserted will never be matched since the login function hashes the password in an attempt to find a match. So what I would need to do is hash the test-user's password as I insert it. How would I go about doing this? This is what my code looks like at the moment:
<?php
include 'functions.php';
class Test extends PHPUnit_Framework_TestCase {
protected function setUp(){
global $mysqli;
$mysqli = new mysqli('localhost', 'xxx', 'xxxxx', 'xxxxx');
$mysqli->query("INSERT INTO members (id, username, pnumber, password) VALUES ('200', 'testbrute', '920314', 'xxxxx')");
}
public function testLogin(){
global $mysqli;
$correctPass = Login('920314','xxxxxx', $mysqli);
$this->assertTrue($correctPass);
$wrongPass = Login('920314','xxxxxxxxx', $mysqli);
$this->assertFalse($wrongPass);
$NoUserExists = Login("980611-5298","--..--..--", $mysqli);
$this->assertFalse($NoUserExists);
}
protected function tearDown(){
$mysqli = new mysqli('localhost', 'xxx', 'xxxxx', 'xxxxx');
$mysqli->query("DELETE FROM members WHERE id IN (200)");
}
}
?>
This is what the login function looks like:
function login($pnumber, $password, $mysqli) {
// Using prepared Statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, password, salt FROM members WHERE pnumber = ? LIMIT 1")) {
$stmt->bind_param('s', $pnumber); // Bind "$pnumber" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
$stmt->bind_result($user_id, $username, $db_password, $salt); // get variables from result.
$stmt->fetch();
$password = hash('sha512', $password.$salt); // hash the password with the unique salt.
if($stmt->num_rows == 1) { // If the user exists
// We check if the account is locked from too many login attempts
if(checkbrute($user_id, $mysqli) == true) {
// Account is locked
// Send an email to user saying their account is locked
return "account locked";
} else {
if($db_password == $password) { // Check if the password in the database matches the password the user submitted.
// Password is correct!
$ip_address = $_SERVER['REMOTE_ADDR']; // Get the IP address of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.
$user_id = preg_replace("/[^0-9]+/", "", $user_id); // XSS protection as we might print this value
$_SESSION['user_id'] = $user_id;
$username = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username); // XSS protection as we might print this value
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512', $password.$ip_address.$user_browser);
// Login successful.
return "login successful";
} else {
// Password is not correct
// We record this attempt in the database
$now = time();
$mysqli->query("INSERT INTO login_attempts (user_id, time) VALUES ('$user_id', '$now')");
return 'pass incorrect';
}
}
} else {
// No user exists.
return 'no exist';
}
}
}
I am new to phpunit and testing in general so please be overly-descriptive.
Forget trying to test against the actual database. As a general rule, you don't want to have your tests dependent on external services if you can help it.
You can inject a mock mysqli object and specify it's behavior. Then you don't have to worry about any values being added to the database or are dependent on having the database even exist.
So in your test rather than declaring a global $mysqli do:
$mockMysqli = $this->getMockBuilder('mysqli')
->disableOriginalConstructor()
->setMethods(array('prepare'))
->getMock();
$mockMysqli->expects($this->once())
->method('prepare')
->will($this->returnValue($mockStmt) //Have to also create a mock mysqli_stmt object
Based on how your function is, you will end up with a few mock objects returning other mock objects which is a code smell that you function is doing too much. Because of this, you would be better off breaking it up into smaller pieces that can then be mocked and tested separately. I find that generally speaking if the function is hard to test, that it is not a good design and should be refactored. Most good designs end up being easy to test with one or two mock objects.

CakeDC admin is accessible by all kinds of users/roles by default, make it secure

I've installed CakeDC Users plugin and I found out that role, is_admin don't function by default. If I login with regular username role=registered and is_admin=0, I can still go to /admin/users/add/. Why are there two types of checks, role and is_admin, what if role=administrator and is_admin=0, or vice-versa?
I am looking for a preferred solution to this problem so I could secure admin section and make use of user roles on different pages. Still, can't understand why is_admin is present, when role=administrator could take care of it all.
I solved the very same issue by adding the following piece of code in "app/Controller/AppController.php" in method "beforeFilter()" :
if (isset($this->params['prefix']) && $this->params['prefix'] == 'admin') {
if ($this->Session->check('Auth.User.role') and 'admin' !== $this->Session->read('Auth.User.role')) {
$this->Auth->deny('*');
return $this->flash('Non admin access unauthorized', '/');
}
}
While I admit this solution is not optimal, it sure does the trick!
This is not an issue of the plugin: You have to implement your auth application wide on your own. The plugin just gives you the basics but does not your job of customizing the app based on the requirements of your client. I recommend you to read this chapter http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
The is_admin check AND role field are there for multiple reasons: Your user can have any role but only if they have is_admin checked they can access an admin area for example. is_admin alone does not allow you to have roles. Both fields are there to cover different scenarios. Again, the plugin is thought to be a kick start and base you can build on. That's what you have to do when you want to customize it.
There is an example that shows pretty much how to use whatever you need:
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#using-controllerauthorize
class AppController extends Controller {
public $components = array(
'Auth' => array('authorize' => 'Controller'),
);
public function isAuthorized($user = null) {
// Any registered user can access public functions
if (empty($this->request->params['admin'])) {
return true;
}
// Only admins can access admin functions
if (isset($this->request->params['admin'])) {
return (bool)($user['role'] === 'admin');
}
// Default deny
return false;
}
}

Winform user authorization via active directory

I have a situation where I am using the following code to verify user membership in AD before executing tasks in my app
using System.Security.Principal;
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole("someGroup");
The above code works fine for machines on my domain, however I do have some machines which are not on my domain on which I have the WINFORM application installed. How can I verify the user membership in AD?
Edit - is there a way to prompt the windows login?
Since your computer is not joined to domain at all, we cannot use WindowsIdentity or WindowsPrincipal and then check its IsInRole() method. The IsInRole() method works only if your computer is joined to the domain and it's using your domain machine account to do S4USelf.
You cannot use LogonUser approach too because your computer won't let you create a logon session from an untrusted forest.
I think we can only query the Active Directory directly to get the information we want. The code in your posted Microsoft KB does not work very well as far as I can tell. It's trying to query from memberOf attribute. The group information is not always available from the memberOf attributes.
I just wrote an IsInRole() function using AccountManagement. I guess this is what you want. The IsInRole() function will call a recursive function IsInGroup() to find out all the groups the user belongs to.
private bool IsInRole(string domain, string username, string password, string role)
{
using (var context = new PrincipalContext(ContextType.Domain, domain, username, password))
{
GroupPrincipal group = GroupPrincipal.FindByIdentity(context, IdentityType.SamAccountName, role);
UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username);
return IsInGroup(user, group);
}
}
private bool IsInGroup(Principal principal, GroupPrincipal group )
{
if (principal.IsMemberOf(group))
return true;
foreach (var g in principal.GetGroups())
{
if (IsInGroup(g, group))
return true;
}
return false;
}
To use this IsInRole() function, you need to provide your domain name and domain credentials. If the username and password provided are wrong, you will get an exception.
You need .NET 3.5 SP1 to use AccountManagement API. Also, you may like to pay attention to this hotfix. The AccountManagement API got some bugs if running in some environment. You may need to apply the hotfix.

Resources