Welcome

This is the generic homepage (aka Aggregate Blog) for a Subtext community website. It aggregates posts from every blog installed in this server. To modify this page, look for the Aggregate skin folder in the Skins directory.

To learn more about the application, check out the Subtext Project Website.

Powered By:
Powered by Subtext

Blog Stats

  • Blogs - 714
  • Posts - 31542
  • Articles - 310
  • Comments - 292438
  • Trackbacks - 222774

Bloggers (posts, last update)

Latest Posts

dbeaver



Free multi-platform database tool for developers, SQL programmers, database administrators and analysts. Supports all popular databases: MySQL, PostgreSQL, MariaDB, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Derby, etc. 

posted @ 7/6/2018 6:14 PM by Alessandro Gervasoni

Summer reading list for the (to be) reformed leader.

posted @ 7/4/2018 12:41 PM by Luca Minudel

Autenticazione e autorizzazione con ASP.NET Core, OpenId Connect e Azure Active Directory

L'uscita di ASP.NET Core – nell'estate del 2016 – si è accompagnata da un sistema di autenticazione/autorizzazione tutto nuovo e basato, come il resto del framework, sul concetto di middleware.

Il middleware è un pezzo di codice che si innesta nella pipeline di ASP.NET con lo scopo di occuparsi di una specifica attività nell'ambito della gestione di una richiesta HTTP. In questo caso, il middleware è responsabile di fare in modo che il richiedente sia autorizzato ad effettuare la richiesta, cioè ad accedere alla relativa risorse. Se il concetto non vi è del tutto chiaro, potete approfondirlo leggendo le nozioni fondamentali di middleware in ASP.NET Core.

Come era forse lecito attenderci, il nuovo sistema si è dimostrato un po' immaturo alla prova dei fatti: in particolare il meccanismo di integrazione tra i diversi middleware di autenticazione era un po' complesso e poteva portare a situazioni incoerenti in determinati scenari.

Il Team di ASP.NET ha quindi deciso di rivedere (nuovamente) il sistema dalle fondamenta e la versione aggiornata è uscita contemporaneamente ad ASP.NET Core 2.

In questa serie di post andremo alla scoperta dei suoi meccanismi di funzionamento, concentrandoci su uno scenario ben definito, quello dell'autenticazione/autorizzazione attraverso Azure Active Directory (in seguito AAD) usando il protocollo OpenId Connect (OIDC).

La maggior parte dei post che trattano questo argomento iniziano immancabilmente con una tediosa spiegazione della differenza tra autenticazione ed autorizzazione. Io mi limito a dire che l'autenticazione è il processo di determinazione dell'identità dell'utente, mentre l'autorizzazione definisce quali siano i suoi permessi dopo che l'identità è stata accertata. Basta. Se volete masochisticamente sviscerare ulteriormente la questione, trovate tonnellate di post in materia.

L'approccio che cercherò di tenere, ove possibile, è di partire dal codice e di introdurre i concetti teorici nel corso della trattazione. Io userò Visual Studio 2017 (versione 15.7, ma Visual Studio Code dovrebbe essere ugualmente adatto) e .NET Core SDK 2.1.200 (per sapere quale versione state utilizzando è sufficiente digitare dotnet --version dal prompt dei comandi).

Per tener conto di chi utilizza IDE diversi da Visual Studio, partiremo creando lo scheletro del progetto a riga di comando usando la CLI dotnet. Dopo esserci posizionati nella cartella in cui vogliamo creare il progetto, i comandi da lanciare sono i seguenti:

  • dotnet new sln --name LearningAuth (se pensiamo di usare Visual Studio e vogliamo creare il file di solution);
  • dotnet new web --name LearningAuth.WebApp (per creare un'applicazione web vuota)
  • dotnet sln add .\LearningAuth.WebApp\LearningAuth.WebApp.csproj (sempre se usiamo Visual Studio, per aggiungere l'applicazione alla solution)

Non mi addentro nei dettagli del progetto creato, perchè la documentazione Microsoft sui concetti fondamentali di ASP.NET Core è decisamente esaustiva.

Il progetto così come lo abbiamo creato si limita a mostrare a video la scritta "Hello world!" indipendentemente da quale sia la risorsa richiesta (ossia la URL digitata) e ovviamente non ha alcuna nozione di risorsa protetta da autorizzazione. Per introdurre il concetto, creiamo un nuovo semplice controller, la relativa view e configuriamo l'applicazione in modo che sia in grado di servirla al client.

Iniziamo creando una cartella Controllers nella root del progetto e aggiungendo un nuovo Controller (che chiameremo HomeController) al suo interno. Il controller avrà per ora un solo metodo Index che dovremo decorare con l'attributo Authorize:

Per creare la view clicchiamo con il destro all'interno del metodo e scegliamo Add View... dal menu contestuale:

Conserviamo le impostazioni di default suggerite da Visual Studio e clicchiamo su Add:

La view di risultante sarà estremamente scarna ma per ora ampiamente sufficiente allo scopo. Ci limiteremo ad aggiungere il codice @User.Identity.Name per stampare il nome dell'utente autenticato:

L'unico problema è che la view si basa una pagina di layout che attualmente non è presente nel nostro progetto. Creiamo allora una nuova cartella Shared sotto Views e aggiungiamo al suo interno una MVC View Layout Page:

Potremmo impostare la pagina di layout direttamente dentro la view, ma è più comodo aggiungere invece una MVC View Start Page e una MVC View Imports Page direttamente sotto la cartella Views. Potranno servirci anche in futuro.

Infine la configurazione: a differenza di quanto avveniva in ASP.NET Core 1, nella versione 2 è stato definito il nuovo metapackage Microsoft.AspNetCore.All che evita la necessità di includere singolarmente la pletora di pacchetti che compongono ASP.NET Core ed EntityFramework Core. Per tale motivo possiamo configurare direttamente il middleware di MVC senza dover manualmente aggiungere il package relativo.

Apriamo quindi il file Startup.cs e configuriamo il middleware di MVC. Per prima cosa dobbiamo registrare i servizi necessari ad MVC nello IoC container che è parte dell'architettura di Dependency Injection nativa di ASP.NET Core. Possiamo farlo aggiungendo il codice relativo nel metodo ConfigureServices. Quindi possiamo aggiungere il middleware MVC alla pipeline nel metodo Configure (che a mio modesto parere sarebbe stato meglio si chiamasse ConfigurePipeline per togliere ogni dubbio, ma tant'è). Il risultato finale deve essere questo:

Per concludere, è opportuno già da subito passare dal protocollo HTTP a quello HTTPS per garantire che le comunicazioni avvengano in forma crittografata in modo tale da prevenire il "tampering" dei dati. Apriamo le proprietà del progetto e nella scheda Debug selezioniamo la casella Enable SSL. Copiamo quindi l'indirizzo (tenetelo a mente perchè ci servirà anche in seguito) e incolliamolo come App URL:

Se preferite potete modificare direttamente il file launchSettings.json impostando le chiavi iisSettings:issExpress:applicationUrl e iisSettings:issExpress:sslPort):

Proviamo a lanciare nuovamente la nostra applicazione è il risultato sarà il seguente:

Il messaggio è forse un po' criptico ma in definitiva ci fornisce due informazioni interessanti: ci dice che l'Authentication Scheme non è stato trovato, e ci dice anche che l'errore si è verificato in un metodo chiamato ChallengeAsync.

Ma cos'è un authentication scheme? È un identificativo univoco del metodo di autenticazione che vogliamo usare nella nostra applicazione, o in una parte di essa. Anche se non è un caso molto frequente, dobbiamo considerare che potrebbe essere necessario gestire più di un tipo di autenticazione all'interno della stessa applicazione (ad esempio distinguendo i controller MVC per i quali vogliamo impostare un'autenticazione basata su cookie da quelli WebAPI per i quali vogliamo invece usare dei token JWT). Per consentire ad ASP.NET di gestire tali scenari, ogni metodo di autenticazione viene registrato tra i servizi con uno specifico identificativo univoco (che altri non è se non un nome in formato stringa).

Quando aggiungiamo un attributo authorize nel codice, possiamo indicare quale metodi di autorizzazione (tra quelli registrati) vogliamo usare per quel particolare controller o action, specificando il relativo schema. Se non lo facciamo (come nel nostro caso), il middleware userà lo schema di default. In questo caso non abbiamo definito neanche quello, da cui l'eccezione che abbiamo riscontrato.

Il problema deriva dal fatto che abbiamo sì richiesto che la nostra action fosse protetta da autorizzazione, ma non abbiamo configurato quale metodo di autenticazione vogliamo usare.

Come detto in apertura, siamo interessati ad esplorare lo scenario dell'autenticazione con Azure Active Directory usando il protocollo OpenId Connect. Sarebbe ora il momento di approfondire i fondamenti teorici di OpenId Connect e del middleware di autenticazione. Ma, visto che il manifesto Agile ci dice che è più importante un "software funzionante" di una "documentazione esaustiva" (sperando che Felice non ci legga) useremo invece un approccio mistico: arriviamo fideisticamente ad un applicazione funzionante e vi prometto poi di tornare indietro per dare un senso alle azioni intraprese.

Cominciamo abbandonando momentaneamente la nostra applicazione per spostarci sul portale di registrazione delle applicazioni di Microsoft. Visto che vogliamo usare AAD, dobbiamo prima "farci conoscere" per instaurare quel rapporto di "trust" tra la nostra applicazione e AAD che ci consentirà di delegargli la parte di autenticazione.

Registriamo quindi la nostra applicazione sul portale dopo aver fatto login con la nostra utenza, cliccando su Aggiungi un'app (non mi chiedete perché alcune pagine sono in italiano e altre in inglese):

Inseriamo il nome della nostra applicazione è clicchiamo su Create (ci sarebbe anche la possibilità di effettuare un setup guidato selezionando la casella relativa, ma per applicazioni ASP.NET Core tale opzione si risolve in un link ad un esempio di configurazione):

Dopo qualche istante veniamo indirizzati alla pagina con le proprietà della nostra applicazione appena registrata. Qui dobbiamo specificare che si tratta di un'applicazione web aggiungendo una nuova piattaforma nella sezione relativa:

Aggiungiamo una piattaforma Web e impostiamo quindi la URL di reindirizzamento, mantenendo la casella Consenti flusso implicito selezionata e ignorando per ora la URL di disconnessione:

La URL va chiaramente impostata in accordo con quella della nostra applicazione (https://localhost:44303/ nel mio caso) aggiungendo l'endpoint signin-oidc (vedremo in seguito di che si tratta).

Possiamo ora salvare le modifiche ma, prima di uscire, annotiamoci l'ID applicazione che si trova in alto sotto al nome:

Ora che Azure Active Directory "conosce" la nostra applicazione, possiamo configurarla per gestire l'autenticazione/autorizzazione in nostra vece per mezzo del protocollo OpenId Connect. Fortunatamente Microsoft ci mette a disposizione un middleware (in ASP.NET Core 2 questa definizione è leggermente scorretta ma passatemi l'imprecisione per evitare ulteriore complessità) che si prende carico di tutte le cerimonie di comunicazione tra la nostra applicazione e un generico provider OIDC.

La prima cosa da fare è, al solito, registrare i servizi nello IoC container:

Questo codice aggiunge i servizi generici del middleware di autenticazione e poi quelli specifici di OIDC. Ricorderete che il messaggio di errore che abbiamo ricevuto in precedenza parlava della mancata definizione di un DefaultChallengeScheme. Per risolvere il problema impostiamo tale schema pari allo schema di default di OIDC (cioè la stringa OpenIdConnect).

Ovviamente, per quanto intelligente possa essere, il middleware non è in grado di sapere con quale provider vogliamo comunicare. È quindi necessario un minimo di configurazione che può essere fatta direttamente nel codice o, come in questo caso, delegata al file di configurazione. Il modo più semplice di farlo è sfruttare il metodo di estensione Bind dell'interfaccia IConfigurationSection. È sufficiente che la struttura della classe di opzioni che vogliamo riempire corrisponda alla struttura della particolare sezione del file di configurazione. Nel nostro caso le chiavi presenti nella sezione OpenIdConnect saranno usate per valorizzare l'oggetto options di classe OpenIdConnectOptions:

L'Authority indica il tenant AAD da interrogare ed è composto dalla URL https://login.microsoftonline.com più l'identificativo del nostro tenant. Come identificativo possiamo usare il nome, ma l'ID è preferibile data la sua immutabilità certa nel tempo. Nel recuperare l'ID del nostro tenant AAD, possiamo aprire il portale di Azure e navigare in Azure Active Directory > Proprietà: ID Directory è il nostro uomo:

Se il vostro account ha accesso a più tenant, ricordatevi di verificare di essere collegati alla directory giusta verificando in altro a destra del portale:

Sistemata l'authority possiamo passare al ClientId: altro non è l'ID Applicazione che abbiamo annotato in fase di registrazione sul portale.

L'ultimo passo è aggiungere il middleware di autenticazione alla pipeline, ovviamente prima che MVC abbia modo di intervenire per gestire la richiesta:

Tutto sembra essere a posto, possiamo provare a lanciare nuovamente la nostra applicazione. Se tutto va bene dovremmo essere reindirizzati alla pagina di login di AAD:

E quindi, dopo essersi autenticati, nuovamente alla nostra applicazione... dove però ci attende una sorpresa:

La prima cosa che notiamo è che AAD ha effettivamente effettuato un redirect alla pagina https://localhost:44303/signin-oidc. Nonostante tale pagina non sia presente nella nostra applicazione, in qualche modo ASP.NET è riuscito a gestirla: vedremo prossimamente come e perchè.

La seconda è che il metodo SignInAsync è andato in eccezione per la mancanza dello schema DefaultSignInScheme, il che ci lascia particolarmente perplessi visto che il login è stato gestito da AAD e che sembrerebbe essere andato a buon fine. Che fa quindi il metodo SignInAsync? E che vuol dire quel messaggio? Lo scopriremo nel prossimo post, per ora limitiamoci a modificare leggermente il codice in Startup.cs in modo da farlo funzionare:

Stavolta ci siamo:

Happy coding!

Il codice di questo post è disponibile su GitHub.

posted @ 5/15/2018 11:31 AM by Giorgio Di Nardo

s3 Browser

free window client for amazon s3
link

posted @ 5/1/2018 10:08 AM by Alessandro Gervasoni

Yarn is a package manager for your code.

https://yarnpkg.com

alternativa a Bower

posted @ 3/20/2018 2:33 PM by Alessandro Gervasoni

Specificare la versione di .netcore in un progetto asp.net core

alll'interno del file .csproj può essere specificata la corretta versione del runtime

<PropertyGroup>
  <RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
  <PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

posted @ 3/20/2018 12:52 PM by Alessandro Gervasoni

Visual Studio 2017 version 15.6, Visual Studio for Mac version 7.4 Released

posted @ 3/15/2018 3:30 PM by Alessandro Gervasoni

Quando il muro rimane bianco..

Segnalo, grazie alla collaborazione di Mauro Servienti un piccolo consiglio per chi posta su UGI tramite l'interfaccia Web dell'amato/odiato SubText.

Nelle opzioni avanzate ricordatevi sempre di spuntare sia "Syndicate on Main Feed" che "Include in Aggregated Site" per apparire sul muro di UGI e nei feed RSS.



Di default l'opzione "Include in Aggregated Site" non risulta infatti marcata ed i post non compaiono nell'aggregatore principale http://blogs.ugidotnet.org.

Devo dire che avendo sempre utilizzando Windows Live Writer, ora sostituito da Open Live Writer (http://openlivewriter.org), non avevo mai avuto bisogno di fare questa operazione.

E adesso mi raccomando.. ricominciate ad imbrattare il muro!

posted @ 3/13/2018 7:05 PM by Leonardo

Prossimi appuntamenti

Ecco la lista dei prossimi appuntamenti dove potrete vedere una mia sessione:

Per ora direi che ci siamo… ho proposto poi delle sessioni ad altre conferenze, in Italia e all’estero, e sto organizzando dei webcast. Vi terrò aggiornati Winking smile

posted @ 3/13/2018 3:23 PM by Lorenzo Barbieri

Stack Traces nuovamente comprensibili

Ops.. è passato un bel pò di tempo dal mio ultimo post su UGI.. lo sapevo! E' successo ancora! :)

FPGA, IoT, Elettronica varia e diversi progetti mi hanno tenuto occupato quanto basta ed aggiornare due blog (per chi non lo sapesse, potete seguirmi anche su http://electro-logic.blogspot.it) è abbastanza impegnativo. In realtà anche lato .NET non mi sono mai fermato (Xamarin, UWP, .NET Core, ...avrei tante tante cose da raccontare!)

Vediamo oggi come si è evoluta nel tempo la Stack Traces in C#, ovvero, semplificando molto, l'elenco cronologico delle chiamate di funzione che ci hanno portato ad una determinata situazione.

Sono ormai passati i tempi (.NET 1.0) dove si aveva uno Stack Trace immediatamente comprensibile come


Con l'aggiunta di nuove funzionalità come i Generics, LINQ, i metodi Lambda, Async, etc.. oggi ci troviamo sempre più spesso ad una situazione di questo tipo (se ci va bene):



Dove si riesce ancora a capire qualcosa, ma il tempo per avere una chiara visione di quello che sta succedendo aumenta inesorabilmente, se non altro per leggere delle informazioni spesso poco rilevanti e rifacenti a meccanismi interni che quasi mai hanno a che vedere coi problemi che come sviluppatori di applicativi (e non di framework) cerchiamo di risolvere.

Il progetto Ben.Demystifier (https://github.com/benaadams/Ben.Demystifier) nasce per riportare la semplicità anche nello Stack Trace, interpretando pattern complessi ma estremamente ripetitivi, conseguenza delle nuove funzioni di .NET, e rendendoli immediatamente comprensibili, rimuovendo così la noiosa ridondanza dai nostri log.

Ecco come diventa lo Stack Trace precedente:



E questo il codice (esempio in .NET Core 2.0, C# 7.2) per generarlo


Come è possibile notare l'utilizzo è immediato, basta chiamare l'Extension Method Demystify() sulle nostre eccezioni per avere una stringa.. demistificata. Veramente impressionante!

Ecco l'esempio dell'autore del progetto, ancora più incisivo, che potete trovare nella pagina principale del progetto:



Personalmente spero che venga in qualche modo direttamente integrato nel futuro .NET Core.
Per il momento utilizziamo la libreria tramite NuGet e diciamo addio a lunghe sessioni di Stack Trace Understanding.

Ciao a tutti!

posted @ 3/11/2018 11:22 AM by Leonardo

Realizzare nuove funzionalit&agrave; non &egrave; il problema, decidere quali realizzare &egrave; il vero nocciolo della questione. @klabcommunity

business-2987962_1920

Anno nuovo, nuova stagione di eventi. Quest’anno per me inizia all’insegna di KLab, il 29 marzo ci troveremo a Fiorenzuola d’Arda presso l’agriturismo Mascuderia. Questa volta il tema si sposterà dalla tecnologia per dare uno sguardo alla parte metodologica.

Io dal mio canto vi racconterò tutto il lavoro che in Particular stiamo facendo per organizzare i processi relativi alla parte di “product management”, che potremmo in qualche modo paragonare con quello che Scrum assegna come responsabilità al PO.

In soldoni potremmo dire che siamo sempre stati {molto?) bravi in quanto a delivery, meno bravi in quanto a decidere cosa realizzare. Compito non facile in una realtà:

  • fluida come la nostra in cui non c’è un capo che decide il cosa il come e il quando.
  • che produce un prodotto che come utente finale ha un altro sviluppatore, il cui prodotto avrà un utente finale.

La distanza tra noi e l’utente finale fa si che i contesti d’uso del nostro prodotto siano molteplici e spesso in contrasto tra loro, le necessità di un cliente on-premise sono facilmente ortogonali a quelle di un cliente su Azure o AWS. Questa dicotomia rende spesso difficile prendere decisioni sulla direzione in cui andare. Vi racconterò il percorso che stiamo facendo per modellare l’azienda e i processi interni al fine di abbracciare questa sorta di requisito non funzionale con cui dobbiamo per forza coesistere.

Il desiderio è che sia di stimolo per tutti per magari provare a cambiare a scollarsi dal “solito modo di fare le cose”.

Vi aspettiamo numerosi, come al solito dopo si mangia!

Maggiori informazioni e iscrizioni: http://www.klabcommunity.org/klab-2018-1-ci-siamo/

posted @ 3/7/2018 11:09 AM by Mauro Servienti

[OT] Slow watches


Orologi con una sola lancetta ..un giro in 24 ore
https://it.slow-watches.com

posted @ 3/3/2018 9:10 AM by Alessandro Gervasoni

Angular CLI e Webpack: cosa c'è nel mio bundle?

Dopo aver sviluppato una applicazione con Angular, ma anche durante in realtà, preparandosi alla build può venire utile sapere cosa c'è nei bundle creati dall'Angular CLI.

Mi è successo da un cliente di Bari di dover fare questa analisi per scoprire come mai non funzionava la build di produzione ed è venuto comdo il tool webpack-bundle-analyzer, se siete curiosi racconto brevemente questa esperienza qui: https://www.tolist.net/Article/Angular-CLI-e-Webpack-cosa-c-nel-mio-bundle-21

posted @ 2/26/2018 2:18 AM by Michele Aponte

Il fascino per le cose che funzionano

movement-2532158_1280

Da sempre ho una sorta di attrazione inspiegabile per le cose semplici che funzionano, soprattutto se funzionano al primo colpo. Inspiegabile perché mi rendo conto che spesso non è condivisa dai mie stimati colleghi informatici, che al contrario spesso sono attratti dalla sovra-ingegnerizzazione e dalla complessità fine a se stessa. È ovviamente una generalizzazione molto spinta, quindi non prendetevela se non siete così ;-)

Sto diventando un fan di prodotti Apple. Ho un iPhone 8, un iPad Pro di cui ho già parlato più di una volta e di cui probabilmente parlerò ancora. Da pochi minuti sono un felice possessore di una coppia di AirPods.

La cosa che mi ha lasciato per l’ennesima volta basito, molto basito, è la semplicità disarmante del setup:

  • avvicini il case al telefono
  • apri il case

Fine. Gli auricolari si connettono e si configurano. Il telefono ti dice ogni volta che nelle vicinanze apri il case:

  • quanto è carico il case, si perché il case è una batteria che ricarica gli auricolari stessi
  • quanto è carico ogni auricolare

Infine, tramite l’account iCloud le impostazioni degli auricolari si propagano a tutti i device connessi con quell’account. Quindi prendete iPad, indossate gli auricolari, avviate la musica e, boom, funziona.

Ogni volta che faccio un’esperienza di questo genere ripenso a X-Box Smart Glass e mi viene da piangere, o, in quanto bergamasco da…biiiip

posted @ 2/23/2018 3:20 PM by Mauro Servienti

Vue.Js with ASP.NET Core MVC

posted @ 2/21/2018 9:17 AM by Alessandro Gervasoni

iPad Pro Smart Keyboard&hellip;

heavy-934552_1280

Come ho detto qualche tempo fa sono un soddisfatto utilizzatore di un iPad Pro. Come dicevo ho anche acquistato la Smart Keyboard e la penna. Della non utilità della penna parleremo un’altra volta.

La tastiera invece è fatta un gran bene, se proprio devo trovare dei difetti, direi che ne ha tre:

  • Una carenza più che un difetto: la mancanza della retroilluminazione, che non è un difetto ma un nice-to-have piuttosto
  • è troppo pesante
  • manca un alloggiamento/gancio per la penna

Siccome la tastiera fa anche da cover, spesso e volentieri vi ritrovate semplicemente ad aprirla e usare il tablet in modalità touch. Per un uso prolungato l’insieme diventa troppo pesante e vi ritrovate spesso a staccare del tutto la cover/tastiera e abbandonarla da qualche parte.

Inoltre l’assenza di un alloggiamento per la penna fa si che se vi portate dietro la penna sperando di poterla utilizzare sono più le volte che rischiate di lasciarla in giro che altro.

posted @ 2/16/2018 4:17 PM by Mauro Servienti

Obfuscar

The Simplest .NET obfuscation tool. And it's free!


https://www.obfuscar.com

posted @ 2/8/2018 12:05 PM by Alessandro Gervasoni

MVC in ASP.NET Core

posted @ 2/4/2018 3:34 PM by Alessandro Gervasoni

UnQlite

An Embeddable NoSQL Database Engine
https://unqlite.org

posted @ 1/29/2018 3:00 PM by Alessandro Gervasoni

&Egrave; un po&rsquo; che bigio, ma ho una buona scusa ;)

2018-01-16 14.27.01

Quelle manine!

A presto.

posted @ 1/26/2018 11:39 AM by Mauro Servienti

Latest Images

From miscellaneous
From miscellaneous
From miscellaneous
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini