11 messaggi dal 11 agosto 2013
Salve,
sto sbattendo la testa da giorni su questo problema : ho acquistato un server dedicato (windows server 2012 + sql server 2012 ) con sopra il mio sito ; ho impostato l'autenticazione di base tramite IIS e configurato il Web.config per l'uso di membership, il problema è che non riesco a farlo autenticare tramite i dati degli utenti registrati su membership ma solo tramite la windows authentication .
Ho letto qualche tutorial sulla personalizzazione del metodo "authorize" ma nessuno mi ha portato benefici!
Quindi la domanda è : come faccio a far autenticare tramite le credenziali degli utenti inseriti con membership?

Grazie
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,

red ha scritto:

ho impostato l'autenticazione di base tramite IIS

Questo richiede che gli utenti siano stati creati in Active Directory (se il webserver fa parte di un dominio) o sulla macchina stessa, come utenti locali di Windows.

Dato che tu hai utenti su Sql Server, non penso che si adatti al tuo caso. Dunque dovresti disabilitare (o disinstallare del tutto) la basic di authentication di IIS, e reimplementarla col C#.

E' molto semplice: dal global.asax, gestisci l'evento AuthenticateRequest e da lì leggi l'intestazione http Authorization. Il suo valore è composto dalla stringa "Basic" e da una parte in base64 che devi decodificare per ottenere lo username e la password.

Se la richiesta non conteneva alcuna intestazione Authorization, devi terminare immediatamente la richiesta con lo status code 401 (Unauthorized) e aggiungendo l'instazione di risposta WWW-Authenticate, come vedi qui:
http://it.wikipedia.org/wiki/Basic_access_authentication#Protocollo

Quando hai ottenuto username e password, puoi verificare la loro validità usando la membership api. Se sono validi, imposta finalmente l'identità per l'utente. Questo lo fai istanziando una GenericIdentity e una GenericPrincipal e assegnandole al thread corrente su Thread.CurrentPrincipal e al contesto della richiesta corrente su HttpContext.Current.User.
Qui vedi un esempio di come assemblare una GenericPrincipal.
http://msdn.microsoft.com/it-it/library/y9dd5fx0(v=vs.110).aspx

ciao,
Moreno
Modificato da BrightSoul il 01 aprile 2014 09.41 -

Enjoy learning and just keep making
11 messaggi dal 11 agosto 2013
Ciao Moreno ,
intanto grazie mille per la tua risposta !

Ho scritto il codice che tu mi hai detto (credo) ed ho disabilitato la basic authentication da IIS !
Ora il server mi chiede l'autenticazione ma con nessuna credenziale mi fa accedere! C'è qualcos'altro che devo considerare? Sul web.config devo lasciare windows authentication(premetto che se elimino questa parte mi da diretto il 401 senza possibilità di inserire le credenziali)?
Ti posto il codice del mio global.asax :

namespace myapp_mvc_beta
{

    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            
        }
        private static void SetPrincipal(IPrincipal principal)
        {
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
            {
                HttpContext.Current.User = principal;
            }
        }
        private static bool CheckPassword(string username, string password)
        {
            //return username == "user" && password == "password";
            return Membership.ValidateUser(username, password);
        }

        private static bool AuthenticateUser(string credentials)
        {
            bool validated = false;
            try
            {
                var encoding = Encoding.GetEncoding("iso-8859-1");
                credentials = encoding.GetString(Convert.FromBase64String(credentials));

                int separator = credentials.IndexOf(':');
                string name = credentials.Substring(0, separator);
                string password = credentials.Substring(separator + 1);

                validated = CheckPassword(name, password);
                if (validated)
                {
                    var identity = new GenericIdentity(name);
                    SetPrincipal(new GenericPrincipal(identity, null));
                }
            }
            catch (FormatException)
            {
                // Credentials were not formatted correctly.
                validated = false;

            }
            return validated;
        }
        protected void Application_AuthenticateRequest(Object sender, EventArgs e)
        {
            var request = HttpContext.Current.Request;
            var authHeader = request.Headers["Authorization"];
            if (authHeader != null)
            {
                var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);


                // RFC 2617 sec 1.2, "scheme" name is case-insensitive
                if (authHeaderVal.Scheme.Equals("basic",
                        StringComparison.OrdinalIgnoreCase) &&
                    authHeaderVal.Parameter != null)
                {
                    AuthenticateUser(authHeaderVal.Parameter);
                }
            }
        }
    }
}



Grazie in anticipo!
Modificato da red il 01 aprile 2014 18.37 -
11.886 messaggi dal 09 febbraio 2002
Contributi
ok, mi sembra un buon lavoro!
Impostando un'identità per l'utente hai completato la parte di autenticazione. Adesso devi svolgere quella di autorizzazione, cioè decidere a quali risorse debbano aver accesso gli utenti (autenticati e non).

red ha scritto:

C'è qualcos'altro che devo considerare?

Sì, devi proteggere la tua applicazione ASP.NET MVC configurando l'attributo [Authorize] come filtro globale, oppure usandolo sui singoli controller o action. Leggi questo articolo di Marco De Sanctis.
http://www.aspitalia.com/script/1118/Proteggere-Intero-Sito-ASP.NET-MVC-Gestendo-Action-Pubbliche.aspx

L'attributo Authorize impedirà l'accesso agli utenti anonimi e vedrai che senza credenziali otterrai un errore 401 (Unauthorized).

red ha scritto:

Sul web.config devo lasciare windows authentication

No, toglila perché non stai autenticando utenti di windows.

Comunque, come mai vuoi usare la basic authentication per l'intera applicazione? Per caso si tratta di un progetto che include solo ApiControllers (è una WebAPI)?

ciao,
Moreno

Enjoy learning and just keep making
11 messaggi dal 11 agosto 2013
Ciao, credo di essermi espresso male! il server non mi fa entrare! Per farmi capire, se disabilito la basic da IIS mi da, appena digito l'indirizzo che dovrebbe richiedere le credenziali , il 401 . Non mi fa vedere proprio i textbox dove inserire i dati! se invece attivo la basic da IIS bypassa totalmente la mia implementazione ed usa la sua basic authentication e credo sia normale. Dove sbaglio?
Comunque è un progetto rest che dovrà interfacciarsi con delle app android e IOs , con la forms authentication ho trovato non pochi problemi tramite app!

Grazie mille per la disponibilità!
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,

red ha scritto:

appena digito l'indirizzo che dovrebbe richiedere le credenziali , il 401

Ah ok, manca la challenge.
Nel metodo Application_AuthenticateRequest aggiungi un else al tuo blocco if. Dobbiamo gestire la situazione in cui la header Authorization non sia stata fornita.
if (authHeader != null) {
  //il codice che hai scritto qui dentro va bene
} else {
  //aggiungo l'else
  //se la authHeader era null, mando questa instestazione al client
  //grazie ad essa, il browser ti mostrerà la finestra di login
  HttpContext.Current.Response.Headers.Add("WWW-Authenticate", "Basic");
  //e magari imposto pure il codice 401
  throw new HttpException(401, "Unauthorized");
}


Comunque, se devi fare dei test non usare il browser perché sarà difficile testare i verbi POST, DELETE e gli altri.

Puoi usare fiddler oppure Postman, che è ideale per questo scopo.

Poi ci sarebbero altre cose di cui parlare...

red ha scritto:

Comunque è un progetto rest

Ok, sappi che se volessi abilitare l'autenticazione solo per gli ApiController e non per gli altri eventuali Controllers che hai nel progetto, l'Application_AuthenticateRequest non andrà bene perché va in esecuzione ad ogni richiesta. Dunque potresti spostare la logica della Basic Authentication in un DelegateHandler, che si può abilitare selettivamente solo per la route di WebApi. Vedi il paragrafo "Per-Route Message Handlers".
http://www.asp.net/web-api/overview/working-with-http/http-message-handlers

E qui vedi un esempio di Marco De Sanctis.
http://www.aspitalia.com/script/1134/Proteggere-Chiave-Servizio-ASP.NET-Web-API.aspx

red ha scritto:

con la forms authentication ho trovato non pochi problemi tramite app!

Già. Se scegli di usare la Basic authentication, ricordati che dovrai quasi obbligatoriamente far viaggiare i dati su HTTPS perché la password viaggia in chiaro, attenzione.
Un modo simile alla Basic Authentication, ma che non espone la password, è l'autenticazione Digest.
http://it.wikipedia.org/wiki/Digest_access_authentication

In alternativa, anziché stare ad implementare tutto, valuta i Mobile Services di Microsoft Azure. Sono il backend ideale per le mobile apps.
Hai esempi d'uso e autenticazione anche per iOs, Android e varie altre piattaforme.
http://www.windowsazure.com/en-us/documentation/articles/mobile-services-ios-get-started-users/

ciao,
Moreno
Modificato da BrightSoul il 01 aprile 2014 23.11 -

Enjoy learning and just keep making
11 messaggi dal 11 agosto 2013
come sempre gentilissimo , ma purtroppo l'errore persiste. anzi ora tira fuori il 500. non capisco se è un errore nel codice o ha qualcosa il server! posso fare altre prove?

Grazie
11.886 messaggi dal 09 febbraio 2002
Contributi
red ha scritto

anzi ora tira fuori il 500

ok, la causa è l'HttpException che ho messo nel codice di ieri, errore mio. Prova invece a mettere questo all'interno del blocco else.
var response = HttpContext.Current.Response;
response.Headers.Add("WWW-Authenticate", "Basic");
response.StatusCode = 401;
response.StatusDescription = "Unauthorized";
response.End();


ciao,
Moreno

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.