Καταρχήν συγχωρείστε με για το μέγεθος του post. Ψιλιάζομαι (πριν κάν ξεκινήσω να το γράφω) ότι θα είναι μεγάλο.
Στόχος μου να δημιουργήσω "ασφαλείς" Web
Services. Δεν αναλύω περαιτέρω το τι επιλογές υπάρχουν για την υλοποίηση της ασφάλειας, γιατί είναι ολόκληρο Forum
από μόνο του. Αποφασίστηκε πάντως οι υπηρεσίες να διασφαλίζονται
μέσω SSL και Client Certificates. Ο IIS δεν θα επιτρέπει
Anonymous Access
. τουναντίον (πσσσσσσσ, τι είπα πάλι) θα
επιβάλλει τη χρήση Client Certificates και θα επιτρέπει μονάχα συγκεκριμένα Certificates. Γνωρίζω ότι δεν είναι ότι
κομψότερο, αλλά τα Web Services θα καλούνται από λίγους και σχετικά
ελεγχόμενους clients. (Περισσότερες πληροφορίες για τα παραπάνω
βρίσκονται
εδώ,
από εκεί άλλωστε άντλησα το ακριβές HowTo
![Wink [;)]](/cs/emoticons/emotion-5.gif)
). Ως έξτρα ασφάλεια
(κερασάκι στην τούρτα) θα επιτρέπεται πρόσβαση μόνο σε συγκεκριμένες IP
διευθύνσεις.
Έχει καλώς ως εδώ. Χρειάζεται όμως να γίνει και Authentication των
clients. Εφόσον ισχύουν όλα τα παραπάνω, θα ήταν μάλλον υπερβολικό να
χρησιμοποιήσω username/password και να τα ελέγχω στη Βάση Δεδομένων.
Θέλω επομένως να κάνω map τα Client Certificates σε συγκεκριμένα
Windows Accounts και έτσι να παίρνω το ποιός είναι ο client από το
Thread.CurrentPrincipal.Identity.Name.
Δουλεύει μια χαρά. Το πρόβλημα έγκειται στη χρήση της μεθόδου
Thread.CurrentPrincipal.IsInRole(strMachineName + "\\" +
strRole), όπου strMachineName είναι το όνομα του Server και
strRole ένα User Group (π.χ. "Guests"). Κατά την κλήση αυτής της
μεθόδου δεν χρησιμοποιείται το
Thread.CurrentPrincipal.Identity (όπως θα έπρεπε)
αλλά το NT AUTHORITY\NETWORK SERVICE. Για παράδειγμα, δοκιμάστε τον
παρακάτω κώδικα :
[WebMethod]
public string WhoAmI() {
string s = String.Empty;
s += "Running as User : " + Thread.CurrentPrincipal.Identity.Name + "\n";
s += "Current Windows Identity : " + System.Security.Principal.WindowsIdentity.GetCurrent().Name;
return s;
}
Προσοχή ότι αν ισχύουν όσα προανέφερα θα πρέπει να κληθεί με
συγκεκριμένο Client Certificate, να έχουν γίνει σωστά οι ρυθμίσεις στον
IIS, κτλ, κτλ. Για ευκολία στην δοκιμή συχνά άφηνα την όλη διαδικασία
με Certificates και SSL και χρησιμοποιούσα Integrated Windows
Authentication και Basic Authentication. Έχοντας κάνει map ένα
certificate στο account μου και εκτελώντας το παραπάνω service, το
αποτέλεσμα είναι πάντοτε το εξής :
Running as User : OLYMPOS\kkara
Current Windows Identity : NT AUTHORITY\NETWORK SERVICE
(προφανώς το PC μου έχει Computer Name OLYMPOS, ίσως γι' αυτό να μη δουλεύει τίποτα, φταίνε οι Θεοί του Ολύμπου
![Smile [:)]](/cs/emoticons/emotion-1.gif)
)
Αν καταλαβαίνω καλά το πως δουλεύει όλο το σκηνικό, τότε αυτό είναι
σωστό αποτέλεσμα αφού ο κώδικας τρέχει με το συγκεκριμένο Account.
Πάντως η παρακάτω μέθοδος δεν επιστρέφει αυτό που θα ήθελα :
/// <summary>Επιστρέφει τα User Groups στα οποία ανήκει ο χρήστης που εκτελεί την υπηρεσία</summary>
[WebMethod]
public string WhichRolesAmIIn() {
string s = String.Empty;
//Βρίσκουμε το DirectoryEntry του μηχανήματος μέσω των DirectoryServices
DirectoryEntry deMachine = new DirectoryEntry("WinNT://OLYMPOS");
foreach(DirectoryEntry child in deMachine.Children)
//Από τα παιδιά του deMachine μας απασχολούν τα Group χρηστών
if (child.SchemaClassName ==
"Group" && Thread.CurrentPrincipal.IsInRole("OLYMPOS\\" +
child.Name))
s += "User " +
Thread.CurrentPrincipal.Identity.Name + " belongs in : " + child.Name +
"\n";
return s;
}
Όταν καλείται η μέθοδος επιστρέφει :
User OLYMPOS\kkara belongs in : CERTSVC_DCOM_ACCESS
Ενώ φυσικά ο χρήστης kkara ανήκει στους Administrators, στους Power
Users, κτλ κτλ. Ελέγχοντας αυτό το user group διαπίστωσα ότι είναι το
μοναδικό στο οποίο οι χρήστες που είναι δηλωμένοι περιγράφονται ως
/Everyone. Τελικά ακόμα δεν έχω καταλάβει ποιόν ακριβώς χρήστη
χρησιμοποιεί όταν κάνει το ερώτημα IsUserInRole.
Δοκίμασα να κάνω και Impersonation, μέσω της εντολής
((WindowsIdentity)Thread.CurrentPrincipal.Identity).Impersonate();
(οπότε τότε αλλάζει το WindowsIdentity.GetCurrent() επιστρέφει όντως
τον χρήστη kkara) αλλά και πάλι το αποτέλεσμα ήταν το ίδιο. Ακόμα κι
όταν δοκίμασα να απλοποιήσω τελείως τα πράγματα και απλά να
χρησιμοποιώ Basic Authentication (χωρίς SSL, χωρίς Credentials, χωρίς
τίποτα) είχα και πάλι τα ίδια ακριβώς αποτελέσματα.
Έχει κανείς καμιά ιδέα για το τι συμβαίνει; Τα νεύρα μου κοντεύουν να
σπάσουν
![Crying [:'(]](/cs/emoticons/emotion-9.gif)
... Θέλω να χρησιμοποιήσω τα Group στα οποία ανήκει ο
χρήστης για να περιορίσω την πρόσβαση σε επίπεδο κώδικα (με το
PrincipalPermissionAttribute) αλλά οποιοδήποτε τρόπο κι αν μου πείτε
για να βρω σε ποιά group ανήκει ο χρήστης, θα είναι ένα βήμα προς την
κατάλληλη κατεύθυνση...
Στερνή μου γνώση να σε είχα πρώτα...