📜 ⬆️ ⬇️

Password Change Notification System [Windows]

Once for our corporate information system, it was necessary to quickly change the saved passwords of users whose names were imported from LDAP.



Traditionally, corporate clients use password-ready systems such as: Microsoft Forefront Identity Manager (FIM) , Oracle Identity Manager , IBM Security Identity Manager, and others.
')
In order not to die at work, while studying a variety of popular corporate creativity, trying to get password changes from xxxXManagers, it is better to immediately contact the domain controller where the new password will come in one way or another.

Moreover, Microsoft AD service allows you to have extensions. And everything would be fine until some custom owners said that everything is good that you are a large and well-known international corporation and for decades we have been using your hardware and software, but we will not put your special software on our server with an AD controller - only hardcore solutions from Microsoft.



The main features of this feature are Password Change Notification Service (PCNS) Configuration Utility . This utility is included with FIM. Starting to learn how to achieve my desired goal, I re-read all possible articles from Microsoft and, with a fright of misunderstanding, how the FIM itself worked, which had about a dozen dependencies on various products, including SharePoint, which already has a couple of dozen dependencies, including MSSQL server, voice search and a lot of other unnecessary and heavy software, for the sake of understanding that in the end FIM are two primitive HTML pages, each of which has a pair of primitive controls for resetting the password.

And to put all this requires a sour server (Microsoft recommends 3-4 servers for this) and about a working day. Having ditched a lot of time and re-reading half of the Internet again, I realized that in the Microsoft view there are at least 3! password paths:
- IM then DC (xxx identification manager to Domain Controller);
- Mail system to DC (Exchange / GroupWise / Domino to Domain Controller);
- DC to Mail system

What I wanted was not included in this list, since I didn’t want to touch either IM or e-mail systems, due to the extreme diversity of these. All this movement of passwords went through FIM Synchronization Service and at the hardware level, for all my disgraces, one minimal configuration server was enough.

Formally, FIMSS is an advanced environment for automated data synchronization of anything with anything (within reasonable limits of course) and has a number of ready-made agents for DC and all known mail agents, and of course a number of user extensions.

Microsoft offers some very intricate step-by-step manuals, but it will be very difficult for a blonde from the street to master it this way, and more than that — it's all not that necessary for my simple case, as I thought. Having much to do with examples of Extension Projects and not getting the result I needed, I turned my eyes back to Google in search of the right decision - and about a miracle - there was one! (most likely I was looking bad again) an example of where the boy in the basic did something and it works (in his words)! The most important thing is to feed Google with the correct code word: IMAPasswordManagement.

In the general, having received a magic pendel in a given direction, I quickly made a similar configuration, which is similar, because by repeating this, it did not work until I had enough time and did not understand how the basic principles of password transfer work.

In order for the password to come to my code written in C #, and there I can romp doing what I want with it - I must:

1. Install FIM Synchronization Service and set the ability to synchronize passwords:


MVExtension.DLL as well as user synchronization agents are generated (texts in C # or VB.NET) directly from FIMSS.

RPC service must be enabled (used to communicate with the Password Change Notification Service (PCNS) Configuration Utility ).

2. Add 2 agents to FIMSS - both are already ready:



All agents have 3 main properties - import, export and synchronize. In our case, 2 is enough: import and synchronization.
Why - I will say later.

1. DCAgent: imports user list from DC
2. RNAgent: imports a list of users from our self-written corporate service (where the reduced list is the same users, that is, by name they match - my agent receives only names derived from LDAP). This agent is created based on the SQL agent (that is, the data (list of users) is received from MSSQL)

There is a small introduction - the password will be transmitted only if the names of both agents match by name.
For this to happen, the FIMSS agents have profiles where they are configured, and then profiles with the necessary commands are launched - first import, then synchronization.

Inside itself, FIMSS keeps everything in the MSSQL database and if you don’t need to care about a limited list from your software, you can recommend (I think Microsoft will discourage such a hack) to read the list of users directly from the internal FIMSS tables, where the list was created by the DCAgent agent: select accountName from [FIMSynchronizationService]. [dbo]. [mms_metaverse]:



Another way is to read the list of users directly from the home base, but here I’m also restricted, so only through dll, which encrypts all data with terrible force.

Setting up agents is also a non-trivial matter and will probably require a separate article, but there is nothing such in the articles from Microsoft. I will point out only a few points that are crucial:

1. In order for RNAgent to pull our Password Extension (the text in C # is also generated from FIMSS) you need to specify it:



This method allows you to get the account name and password in the clear and call the method from our DLL in C ++ that encrypts the result and sends the REST service to our corporate server. Bingo.

public void SetPassword( CSEntry csentry, string NewPassword ) { Log(String.Format("SetPassword entered: [{0}] is : [{1}]", csentry.DN.ToString(), NewPassword)); UNICODE_STRING User = InitLsaString(csentry.RDN); UNICODE_STRING Pwd = InitLsaString(NewPassword); SendPasswordToMyServer(User, Pwd); } 


2. DCAgent: Specify the password to whom


After the agents are created, you need someone to kick them so that the import and synchronization takes place regularly. We have established for ourselves that once a day is quite enough, but you can do it once every 5 minutes. The main problem is that in a large company with tens of thousands of employees, imports from DC can take a very long time and therefore for regular imports it is better to use not Full Import, but Delta Import. Microsoft offers the following solution - pull profiles with TASK SCHEDULER .
If you click on the link, you can see that in the profile creation dialog you can generate C # / VB which you can run on a schedule.

For some, this will be enough, but we decided to complicate our task and transfer the list of users from our remote server via an encrypted channel without using standard Microsoft tools.

That is, on the same machine, to have C # Windows Service, which will read the xml timer, decode it and insert it into our database table, from which the RNAgent will already read.

Primary Service Code
  protected bool Process() { IntPtr ptrUserList = new IntPtr(); bool result = false; try { ptrUserList = GetUserList(); string userList = StringFromNativeUtf8(ptrUserList); int cnt_imported = -1; result = SaveAccounts(userList, ref cnt_imported); // LDAP users will appear in [RNService].[dbo].[CoreAccount] result = result ? DCAgent(m_dcagent_guid) : false; // sync users from DC result = result ? RNAgent(m_rnagent_guid) : false; // sync users from [RNService].[dbo].[CoreAccount] eventLogRN.WriteEntry("Imported users: " + cnt_imported ); } catch (Exception ex) { eventLogRN.WriteEntry("Process: " + ex.Message, EventLogEntryType.Error); return false; } DisposeUserList(ptrUserList); m_timer.Interval = m_servicePollInterval; // use interval from registry return result; } public bool SaveAccounts(string userList, ref int cnt_imported) { string con_str = @"Data Source=" + m_serverName + ";Initial Catalog=RNService;Integrated Security=True"; cnt_imported = -1; using (SqlConnection cnn = new SqlConnection(con_str)) { cnn.Open(); using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = cnn; cmd.CommandType = CommandType.Text; cmd.CommandText = "TRUNCATE TABLE CoreAccount;" + " INSERT INTO CoreAccount SELECT XCvalue(N'@name', N'nvarchar(448)') FROM " + " (SELECT @data AS XML_DATA) DATA CROSS APPLY DATA.XML_DATA.nodes(N'/response/users/user') as X(C); " + " SELECT @@ROWCOUNT AS usercnt; "; cmd.Parameters.Add("@data", SqlDbType.Xml); try { cmd.Parameters[0].Value = userList; SqlDataReader SqlDataReader = cmd.ExecuteReader(); if (!SqlDataReader.IsClosed && SqlDataReader.HasRows) { if( SqlDataReader.Read() ) { cnt_imported = SqlDataReader.GetInt32(0); } } } catch (Exception ex) { eventLogRN.WriteEntry("UpdateCoreAccounts: " + ex.Message, EventLogEntryType.Error); cnn.Close(); return false; } } cnn.Close(); return true; } } 




In the same service, and pull the profiles of the agents that we have generated, which will relieve our customers of torment with TASK SCHEDULER.
In my case, they simply remove the profile guides from the script and put them in the register.

  public bool Agent(string agentName, string guid) { if (guid == null_guid) { return true; // required manual syncronization } try { ConnectionOptions opt = new ConnectionOptions(); opt.Authentication = AuthenticationLevel.PacketPrivacy; ManagementScope myScope = new ManagementScope("root\\MicrosoftIdentityIntegrationServer", opt); string sQuery = "GUID='{" + guid + "}'"; SelectQuery myQuery = new SelectQuery("MIIS_ManagementAgent", sQuery); ManagementObjectSearcher searcher = new ManagementObjectSearcher(myScope, myQuery); foreach (ManagementObject ma in searcher.Get()) { eventLogRN.WriteEntry(agentName + ".Execute( \"ImportSync\" )..."); ma.InvokeMethod("Execute", new object[1] { "ImportSync" }); } } catch (Exception ex) { eventLogRN.WriteEntry( ex.Message, EventLogEntryType.Error); } return true; } 

Source: https://habr.com/ru/post/305698/


All Articles