Makale Özeti

Web sitenizin güvenliği için Windows Authentication kullandığınızda veya kullanıcılarla bilgi paylaşımı için Sharepoint portallerinden faydalandığınızda şirket dışı kullanıcıların şifrelerini istedikleri zaman değiştirmeleri problem oluşturabilir. Bu işlem için şirkete gelip şifrelerini ağa bağlı makinelerden değiştirmeleri veya sizin şifreyi değiştirip onlara bildirmeniz gerekir. Ancak her iki yöntem de güvenlik ve kolaylık açısından uygun değildir. Kullanıcılara bu imkanı sunmak üzere bir şifre değiştirme sayfası veya webpart’ı geliştirebilirsiniz. Bu makalede web üzerinden Active Directory’deki kullanıcı şifresini değiştirebilmek için gerekli bilgileri bulacaksınız.

Makale

Web üzerinden Active Directory’de kayıtlı kullanıcının şifresini değiştirmek için System.DirectoryServices namespace’indeki class’lardan faydalanacağız.  İzleyeceğimiz adımlar şunlar olacak:

  1. Active Directory sunucuna erişilecek
  2. Kullanıcı adı ve şifresi alınan kullanıcı Active Directory nesneleri içinden bulunacak
  3. Kullanıcının şifresi değiştirilecek
  4. Bilgiler kaydedilecek

Ayrıca bu işlemler sırasında oluşabilecek hataları yakalayıp kullanıcıya bu hataların sebebi ile ilgili açıklayıcı bilgiler vereceğiz.

Önce formu resimdeki gibi hazırlayalım.  Textbox’ların isimlerini anlaşılır olması açısından içlerine yazdım.  Güvenlik açısından Textbox’ların TextMode özelliklerini Password olarak değiştirmenizi öneririm.

lblKullanıcıAdi Label’ına Page_Load metodunda sayfaya giriş yapmış kullanıcının ismini yazıdırıyorum. 

private void Page_Load(object sender, System.EventArgs e

{

    lblKullaniciAdi.Text=Page.User.Identity.Name;

}

txtYeniSifre textbox’ının yanına CompareValidator kontrolünü ekledim.  CompareValidator kontrolü txtYeniSifre ile txtYeniSifreTekrar alanlarına girilen değerlerin aynı olup olmadığını kontrol ediyor.  Değiştir butonunun click olayına ise şu kodları yazalım:

 

Active Directory sunucusuna erişmek için LDAP’tan faydalanacağız. LDAP (Lightweight Directory Access Protocol) kısaca güvenlik bilgileri, e-mail adresleri gibi bilgilerin saklandığı TCP/IP üzerinden çalışan veritabanına bağlanmak için kullanılan protokoldür.  Sunucuya bağlanmak için LDAP cümlesi aşağıdakine benzer şekilde oluşturulur:

string LDAP="LDAP://serveradi/DC=ornek,DC=com,DC=tr";

Burada serveradi yerine Active Directory’nin kurulu olduğu bilgisayarın adı yazılır.  DC’ler ise domain’nizi tanımlar.

Sunucuya erişim sırasında bir de kullanıcı adı ve şifreye ihtiyaç duyacağımızdan, sayfaya login olan kullanıcının bilgileri almamız gerekiyor.

string kullaniciAdi = Page.User.Identity.Name.Split(@"\".ToCharArray())[1];

Böylece logon olan kullanıcının adını almış oluyoruz.  Gelen değer örneğin alanAdi\kullaniciAdi şeklideyse yukarıdaki kod ile bu değeri parçalayıp sadece ihtiyacımız olan kullanıcı adı bilgisini alıyoruz.  Eğer sayfada windows authentication kullanmıyorsanız kullanıcının adını bir textbox yardımıyla almanız gerekir.

Bu adımdan sonra Active Directory erişimi için gerekli DirectoryEntry nesnesini oluşturmalıyız.  Buradan sonra kullanacağımız class’lar System.DirectoryServices namespace’i altında olacağından bu namespace’i import etmeyi unutmayın.

DirectoryEntry rootDSE = new DirectoryEntry(String.Format(LDAP), kullaniciAdi, eskiSifre, AuthenticationTypes.Secure);

Nesnenin adı aslında bir kısaltmadan geliyor: root Directory Service Entry.  rootDSE, kullanıcının ActiveDirectory’deki bilgilerine erişim yapmak için bir başlangıç nesnesidir.  Active Directory’ye bağlanabilmek için şifresini değiştirmek istediğimiz kullanıcının güvenlik bilgilerini kullanıyoruz.  Bu nesneyi oluşturduktan sonra Active Directory’ye bağlamamız gerekiyor.  Bunun için erişmeye çalıştığımız Active Directory’nin Defaultnamingcontext özelliğini kullanarak yeni bir DirectoryEntry nesnesi oluşturuyoruz:

string rootDN = (string)(rootDSE.Properties["defaultNamingContext"].Value);

DirectoryEntry searchRoot = new DirectoryEntry(String.Format(LDAP, rootDN), kullaniciAdi, eskiSifre, AuthenticationTypes.Secure);

Oluşturduğumuz yeni DirectoryEntry nesnesini şifresini değiştirmek istediğimiz kullancıyı aramak için kullanacağız.  Arama işlemi için önce bir DirectorySearcher tanımlıyoruz:

DirectorySearcher searcher = new DirectorySearcher(searchRoot);

Daha sonra arama kriterimizi tanımlıyoruz.  Kriterimiz Active Directory’deki SAMAccountName özelliğini kullnacak.  Bu özellik aslında kullanıcı ismidir ve her kullanıcı için mutlaka farklıdır.

searcher.Filter=String.Format("(&(objectClass=user)(sAMAccountName={0}))", kullaniciAdi);

Buradaki objectClass=user tanımlaması ile aramayı user tipindeki nesneler üzerinde yapacağımızı bildirmiş oluyoruz.

searcher.SearchScope = SearchScope.Subtree;

searcher.CacheResults = false;

SearchScope’u tüm alt nesneleri de arayacak şekilde Subtree olarak tanımlıyoruz.  Sonuçların istemci bilgisayarda cache’lenmesini önlemek için CacheResults’ı false olarak atıyoruz.  Arama sonucundan gelecek veri sayısı fazla ise bu özellik false olarak ayarlanmalıdır.  Bizim uygulamamız için çok kritik değil ancak örneğin belirli bir gruba üye kullanıcıları çekecek olursanız bunu kullanmanızı öneririm.

Artık arama sonuçlarını alabiliriz.  Gelen sonuçları bir SearchResultCollection nesnesi aracılığıyla alıyoruz:

SearchResultCollection results = searcher.FindAll();

Daha sonra aradığımız kullanıcıyı bir DirectoryEntry nesnesine atıyoruz:

foreach(SearchResult result in results)

{

      userEntry = result.GetDirectoryEntry();

      break;

}

Burada bir kontrol yapacağız.  Eğer arama sonucu bir nesne dönmemişse bir Exception fırlatmamız gerekiyor.  Aslında yukarıdaki kodlarla mutlaka bir kullanıcı dönecektir öünkü Active Directory’ye bağlanmak için aradığımız kullanıcının bilgilerinden faydalanıyoruz.  Ancak bağlanmak için başka bir kullanıcıyı örneğin Domain Admin’i kullanabilirdik.  Arama kritelerimizi de şifresini değiştirmek istediğimiz kullancının bilgilerine göre oluşturabilirdik.  İşte bu durumda aradığımız kullanıcıyı bulamama olasılığımız mevcut.  Bu durumu yakalamak için döngünün ardından userEntry’yi kontrol ediyoruz:

if (userEntry==null)

{

      throw new InvalidOperationException("Domain'de böyle bir kullanıcı yok");

}

Eğer userEntry nesnesi null değilse artık şifre değiştirme işlemine başlayabiliriz.

userEntry.Invoke("ChangePassword", new object[] {eskiSifre, yeniSifre});

ChangePassword metodu şifresi bilinen kullanıcıya yeni bir şifre atamak için kullanılır.  Şifresini bilmediğiniz bir kullanıcıya yeni şifre ataybilmek için SetPassword metodunu kullanmalısınız.  Ancak bu durumda da Active Directory’ye Administrator hakları ile bağlanmış olmanız gerekir.

Değişiklikleri Active Directory’ye yansıtmak için:

userEntry.CommitChanges();                    

Response.Write("Şifreniz başarıyla değiştirilmiştir.");

Böylece kullanıcının şifresini değiştirmiş olursunuz.  Burada yakalamız gereken bir hata durumu daha var.  Eğer kullanıcı eski şifresini yanlış girmişse bu durumu kullancıya bildirmemiz gerekir.  Bunun için şifre değiştirme kodlarını try_catch bloğuna alarak kodlar tarafından fırlatılacak COMException’ı yakalamamız gerekir:

try

{

//Şifre değiştirme kodları

}

catch(System.Runtime.InteropServices.COMException ex)

{

if(ex.ErrorCode==-2147023570)

      {

            Response.Write("Eski şifrenizi yanlış girdiniz.  Şifreniz değiştirilememiştir.");

      }

}

Böylece kullanıcıyı yanlış şifre girdiği konusunda uyararak hesabını kitlemesini önlemiş oluruz.  Bu sayfayı SSL kullanarak daha güvenli bir hale getirebilirsiniz.  Ayrıca userEntry nesnesini kullanarak ActiveDirectory’deki kullanıcıyla ilgili diğer bilgilere ulaşmanız da mümkün.

Konu ile ilgili sorularınız için elifnur.guner@yazgelistir.com adresinden bana ulaşabilirsiniz.

Kaynak Kodlar