Index: gtk/gtkmarshalers.list
===================================================================
--- gtk/gtkmarshalers.list	(revision 22560)
+++ gtk/gtkmarshalers.list	(working copy)
@@ -97,6 +97,7 @@
 VOID:STRING
 VOID:STRING,BOXED
 VOID:STRING,STRING
+VOID:STRING,STRING,STRING
 VOID:STRING,INT,POINTER
 VOID:STRING,UINT,FLAGS
 VOID:STRING,UINT,FLAGS,UINT
Index: gtk/gtkprintbackend.c
===================================================================
--- gtk/gtkprintbackend.c	(revision 22560)
+++ gtk/gtkprintbackend.c	(working copy)
@@ -25,6 +25,7 @@
 
 #include "gtkintl.h"
 #include "gtkmodules.h"
+#include "gtkmarshalers.h"
 #include "gtkprivate.h"
 #include "gtkprintbackend.h"
 #include "gtkprinter-private.h"
@@ -49,6 +50,9 @@
   guint printer_list_requested : 1;
   guint printer_list_done : 1;
   GtkPrintBackendStatus status;
+  char *hostname;
+  char *username;
+  char *password;
 };
 
 enum {
@@ -57,6 +61,7 @@
   PRINTER_ADDED,
   PRINTER_REMOVED,
   PRINTER_STATUS_CHANGED,
+  REQUEST_PASSWORD,
   LAST_SIGNAL
 };
 
@@ -353,6 +358,10 @@
 static GList *              fallback_printer_list_papers           (GtkPrinter          *printer);
 static GtkPageSetup *       fallback_printer_get_default_page_size (GtkPrinter          *printer);
 static GtkPrintCapabilities fallback_printer_get_capabilities      (GtkPrinter          *printer);
+static void                 request_password                       (GtkPrintBackend     *backend,
+                                                                    const gchar         *hostname,
+                                                                    const gchar         *username,
+                                                                    const gchar         *prompt);
   
 static void
 gtk_print_backend_class_init (GtkPrintBackendClass *class)
@@ -372,6 +381,7 @@
   class->printer_list_papers = fallback_printer_list_papers;
   class->printer_get_default_page_size = fallback_printer_get_default_page_size;
   class->printer_get_capabilities = fallback_printer_get_capabilities;
+  class->request_password = request_password;
   
   g_object_class_install_property (object_class, 
                                    PROP_STATUS,
@@ -425,6 +435,14 @@
 		  NULL, NULL,
 		  g_cclosure_marshal_VOID__OBJECT,
 		  G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
+  signals[REQUEST_PASSWORD] =
+    g_signal_new (I_("request-password"),
+		  G_TYPE_FROM_CLASS (class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
+		  NULL, NULL,
+		  _gtk_marshal_VOID__STRING_STRING_STRING,
+		  G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
 }
 
 static void
@@ -437,6 +455,9 @@
   priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
 					  (GDestroyNotify) g_free,
 					  (GDestroyNotify) g_object_unref);
+  priv->hostname = NULL;
+  priv->username = NULL;
+  priv->password = NULL;
 }
 
 static void
@@ -640,6 +661,171 @@
 						       dnotify);
 }
 
+void 
+gtk_print_backend_set_password (GtkPrintBackend *backend,
+                                const gchar     *hostname,
+                                const gchar     *username,
+                                const gchar     *password)
+{
+  g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
+
+  if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
+    GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, hostname, username, password);
+}
+
+static void
+store_password (GtkEntry        *entry,
+                GtkPrintBackend *backend)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+
+  if (priv->password != NULL)
+    {
+      memset (priv->password, 0, strlen (priv->password));
+      g_free (priv->password);
+    }
+
+  priv->password = g_strdup (gtk_entry_get_text (entry));
+}
+
+static void
+store_username (GtkEntry        *entry,
+                GtkPrintBackend *backend)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+
+  g_free (priv->username);
+  priv->username = g_strdup (gtk_entry_get_text (entry));
+}
+
+static void
+password_dialog_response (GtkWidget       *dialog,
+                          gint             response_id,
+                          GtkPrintBackend *backend)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+
+  if (response_id == GTK_RESPONSE_OK)
+    gtk_print_backend_set_password (backend, priv->hostname, priv->username, priv->password);
+  else
+    gtk_print_backend_set_password (backend, priv->hostname, priv->username, NULL);
+
+  if (priv->password != NULL)
+    {
+      memset (priv->password, 0, strlen (priv->password));
+      g_free (priv->password);
+      priv->password = NULL;
+    }
+
+  g_free (priv->username);
+  priv->username = NULL;
+
+  gtk_widget_destroy (dialog);
+
+  g_object_unref (backend);
+}
+
+static void
+request_password (GtkPrintBackend *backend,
+                  const gchar     *hostname,
+                  const gchar     *username,
+                  const gchar     *prompt)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+  GtkWidget *dialog, *username_box, *password_box, *main_box, *label, *icon, *vbox,
+            *password_prompt, *username_prompt,
+            *password_entry, *username_entry;
+  gchar     *text;
+  gchar     *markup;
+
+  dialog = gtk_dialog_new_with_buttons (_("Authentication"), NULL, GTK_DIALOG_MODAL, 
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_OK, GTK_RESPONSE_OK,
+                                        NULL);
+
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+  main_box = gtk_hbox_new (FALSE, 0);
+
+  /* Left */
+  icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG);
+  gtk_misc_set_alignment (GTK_MISC (icon), 0.5, 0.0);
+  gtk_misc_set_padding (GTK_MISC (icon), 6, 6);
+
+
+  /* Right */
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_widget_set_size_request (GTK_WIDGET (vbox), 320, -1);
+
+  text = g_strdup_printf (prompt);
+
+  /* Right - 1. */
+  label = gtk_label_new (NULL);
+  markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"large\">%s</span>", text);
+  gtk_label_set_markup (GTK_LABEL (label), markup);
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  gtk_widget_set_size_request (GTK_WIDGET (label), 320, -1);
+  g_free (text);
+  g_free (markup);
+
+
+  /* Right - 2. */
+  username_box = gtk_hbox_new (TRUE, 0);
+
+  username_prompt = gtk_label_new (_("Username:"));
+  gtk_misc_set_alignment (GTK_MISC (username_prompt), 0.0, 0.5);
+
+  username_entry = gtk_entry_new ();
+  gtk_entry_set_text (GTK_ENTRY (username_entry), username);
+
+
+  /* Right - 3. */
+  password_box = gtk_hbox_new (TRUE, 0);
+
+  password_prompt = gtk_label_new (_("Password:"));
+  gtk_misc_set_alignment (GTK_MISC (password_prompt), 0.0, 0.5);
+
+  password_entry = gtk_entry_new ();
+  gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
+  gtk_entry_set_activates_default (GTK_ENTRY (password_entry), TRUE);
+
+
+  /* Packing */
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_box, TRUE, FALSE, 0);
+
+  gtk_box_pack_start (GTK_BOX (main_box), icon, FALSE, FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (main_box), vbox, FALSE, FALSE, 6);
+
+  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), username_box, FALSE, TRUE, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), password_box, FALSE, TRUE, 6);
+
+  gtk_box_pack_start (GTK_BOX (username_box), username_prompt, TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (username_box), username_entry, TRUE, TRUE, 0);
+
+  gtk_box_pack_start (GTK_BOX (password_box), password_prompt, TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (password_box), password_entry, TRUE, TRUE, 0);
+
+
+  gtk_widget_grab_focus (password_entry);
+
+  priv->hostname = g_strdup (hostname);
+  priv->username = g_strdup (username);
+
+  g_signal_connect (password_entry, "changed",
+                    G_CALLBACK (store_password), backend);
+
+  g_signal_connect (username_entry, "changed",
+                    G_CALLBACK (store_username), backend);
+
+  g_object_ref (backend);
+  g_signal_connect (G_OBJECT (dialog), "response",
+                    G_CALLBACK (password_dialog_response), backend);
+
+  gtk_widget_show_all (dialog);
+}
+
 void
 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
 {
Index: gtk/gtkprintbackend.h
===================================================================
--- gtk/gtkprintbackend.h	(revision 22560)
+++ gtk/gtkprintbackend.h	(working copy)
@@ -120,14 +120,22 @@
 							      GtkPrinter          *printer);
   void                  (*printer_status_changed)            (GtkPrintBackend     *backend,
 							      GtkPrinter          *printer);
+  void                  (*request_password)                  (GtkPrintBackend     *backend,
+                                                              const gchar         *hostname,
+                                                              const gchar         *username,
+                                                              const gchar         *prompt);
 
+  /* not a signal */
+  void                  (*set_password)                      (GtkPrintBackend     *backend,
+                                                              const gchar         *hostname,
+                                                              const gchar         *username,
+                                                              const gchar         *password);
+
   /* Padding for future expansion */
   void (*_gtk_reserved1) (void);
   void (*_gtk_reserved2) (void);
   void (*_gtk_reserved3) (void);
   void (*_gtk_reserved4) (void);
-  void (*_gtk_reserved5) (void);
-  void (*_gtk_reserved6) (void);
 };
 
 GType   gtk_print_backend_get_type       (void) G_GNUC_CONST;
@@ -144,6 +152,10 @@
 						    GDestroyNotify           dnotify);
 GList *     gtk_print_backend_load_modules         (void);
 void        gtk_print_backend_destroy              (GtkPrintBackend         *print_backend);
+void        gtk_print_backend_set_password         (GtkPrintBackend         *backend, 
+                                                    const gchar             *hostname,
+                                                    const gchar             *username,
+                                                    const gchar             *password);
 
 /* Backend-only functions for GtkPrintBackend */
 
Index: gtk/gtkprintunixdialog.c
===================================================================
--- gtk/gtkprintunixdialog.c	(revision 22560)
+++ gtk/gtkprintunixdialog.c	(working copy)
@@ -757,7 +757,10 @@
     priv->print_backends = gtk_print_backend_load_modules ();
 
   for (node = priv->print_backends; node != NULL; node = node->next)
-    printer_list_initialize (dialog, GTK_PRINT_BACKEND (node->data));
+    {
+      GtkPrintBackend *backend = node->data;
+      printer_list_initialize (dialog, backend);
+    }
 }
 
 static void
Index: modules/printbackends/cups/gtkcupsutils.c
===================================================================
--- modules/printbackends/cups/gtkcupsutils.c	(revision 22560)
+++ modules/printbackends/cups/gtkcupsutils.c	(working copy)
@@ -39,10 +39,12 @@
 static void _post_write_request (GtkCupsRequest *request);
 static void _post_write_data    (GtkCupsRequest *request);
 static void _post_check         (GtkCupsRequest *request);
+static void _post_auth          (GtkCupsRequest *request);
 static void _post_read_response (GtkCupsRequest *request);
 
 static void _get_send           (GtkCupsRequest *request);
 static void _get_check          (GtkCupsRequest *request);
+static void _get_auth           (GtkCupsRequest *request);
 static void _get_read_data      (GtkCupsRequest *request);
 
 struct _GtkCupsResult
@@ -69,6 +71,7 @@
   _post_write_request,
   _post_write_data,
   _post_check,
+  _post_auth,
   _post_read_response
 };
 
@@ -76,6 +79,7 @@
   _connect,
   _get_send,
   _get_check,
+  _get_auth,
   _get_read_data
 };
 
@@ -101,12 +105,13 @@
 }
 
 GtkCupsRequest *
-gtk_cups_request_new (http_t             *connection,
-                      GtkCupsRequestType  req_type, 
-                      gint                operation_id,
-                      GIOChannel         *data_io,
-                      const char         *server,
-                      const char         *resource)
+gtk_cups_request_new_with_username (http_t             *connection,
+                                    GtkCupsRequestType  req_type, 
+                                    gint                operation_id,
+                                    GIOChannel         *data_io,
+                                    const char         *server,
+                                    const char         *resource,
+                                    const char         *username)
 {
   GtkCupsRequest *request;
   cups_lang_t *language;
@@ -123,6 +128,8 @@
   request->type = req_type;
   request->state = GTK_CUPS_REQUEST_START;
 
+  request->password_state = GTK_CUPS_PASSWORD_NONE;
+
    if (server)
     request->server = g_strdup (server);
   else
@@ -171,15 +178,37 @@
                                    "attributes-natural-language", 
                                    NULL, language->language);
 
-  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
-                                   "requesting-user-name",
-                                   NULL, cupsUser ());
-  
+  if (username != NULL)
+    gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                                     "requesting-user-name",
+                                     NULL, username);
+  else
+    gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                                     "requesting-user-name",
+                                     NULL, cupsUser ());
+
   cupsLangFree (language);
 
   return request;
 }
 
+GtkCupsRequest *
+gtk_cups_request_new (http_t             *connection,
+                      GtkCupsRequestType  req_type, 
+                      gint                operation_id,
+                      GIOChannel         *data_io,
+                      const char         *server,
+                      const char         *resource)
+{
+  return gtk_cups_request_new_with_username (connection,
+                                             req_type,
+                                             operation_id,
+                                             data_io,
+                                             server,
+                                             resource,
+                                             NULL);
+}
+
 static void
 gtk_cups_result_free (GtkCupsResult *result)
 {
@@ -205,7 +234,14 @@
 
   g_free (request->server);
   g_free (request->resource);
+  if (request->password != NULL)
+    {
+      memset (request->password, 0, strlen (request->password));
+      g_free (request->password);
+    }
 
+  g_free (request->username);
+
   gtk_cups_result_free (request->result);
 
   g_free (request);
@@ -786,12 +822,83 @@
           return;
         }
     }
-   else
+  else if (http_status == HTTP_UNAUTHORIZED)
     {
+      request->state = GTK_CUPS_POST_CHECK;
+      request->poll_state = GTK_CUPS_HTTP_READ;
+
+      request->attempts = 0;
+      return;
+    }
+  else
+    {
       request->attempts++;
     }
 }
 
+static void
+_post_auth (GtkCupsRequest *request)
+{
+  if (request->password_state == GTK_CUPS_PASSWORD_HAS)
+    {
+      if (request->password == NULL)
+        {
+          request->state = GTK_CUPS_POST_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+          gtk_cups_result_set_error (request->result, 
+                                     GTK_CUPS_ERROR_AUTH,
+                                     0,
+                                     1,
+                                     "Canceled by user");
+        }
+      else
+        request->state = GTK_CUPS_POST_CHECK;
+    }
+}
+
+static void
+_get_auth (GtkCupsRequest *request)
+{
+  if (request->password_state == GTK_CUPS_PASSWORD_HAS)
+    {
+      if (request->password == NULL)
+        {
+          request->state = GTK_CUPS_GET_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+          gtk_cups_result_set_error (request->result, 
+                                     GTK_CUPS_ERROR_AUTH,
+                                     0,
+                                     1,
+                                     "Canceled by user");
+        }
+      else
+        request->state = GTK_CUPS_GET_CHECK;
+    }
+}
+
+/* Very ugly hack: cups has a stupid synchronous password callback 
+ * that doesn't even take the request or user data parameters, so 
+ * we have to use a static variable to pass the password to it.
+ * Not threadsafe !
+ * The callback sets cups_password to NULL to signal that the 
+ * password has been used.
+ */
+static char *cups_password;
+static char *cups_username;
+
+static const char *
+passwordCB (const char *prompt)
+{
+  char *pwd = cups_password;
+  cups_password = NULL;
+
+  cupsSetUser (cups_username);
+
+  return pwd;
+}
+
 static void 
 _post_check (GtkCupsRequest *request)
 {
@@ -810,18 +917,91 @@
     }
   else if (http_status == HTTP_UNAUTHORIZED)
     {
-      /* TODO: callout for auth */
-      g_warning ("NOT IMPLEMENTED: We need to prompt for authorization");
-      request->state = GTK_CUPS_POST_DONE;
-      request->poll_state = GTK_CUPS_HTTP_IDLE;
+      int auth_result = -1;
+      httpFlush (request->http);
+
+      if (request->password_state == GTK_CUPS_PASSWORD_APPLIED)
+        {
+          request->password_state = GTK_CUPS_PASSWORD_NOT_VALID;
+          request->state = GTK_CUPS_POST_AUTH;
+          request->need_password = TRUE;
+
+          return;
+        }
+
+      /* Negotiate */
+      if (strncmp (httpGetField (request->http, HTTP_FIELD_WWW_AUTHENTICATE), "Negotiate", 9) == 0)
+        {
+          auth_result = cupsDoAuthentication (request->http, "POST", request->resource);
+        }
+      /* Basic, BasicDigest, Digest and PeerCred */
+      else
+        {
+          if (request->password_state == GTK_CUPS_PASSWORD_NONE)
+            {
+              cups_password = g_strdup("");
+              cups_username = request->username;
+              cupsSetPasswordCB (passwordCB);
+
+              /* This call success for PeerCred authentication */
+              auth_result = cupsDoAuthentication (request->http, "POST", request->resource);
+
+              if (auth_result != 0)
+                {
+                  /* move to AUTH state to let the backend 
+                   * ask for a password
+                   */ 
+                  request->state = GTK_CUPS_POST_AUTH;
+                  request->need_password = TRUE;
+
+                  return;
+                }
+            }
+          else
+            {
+              cups_password = request->password;
+              cups_username = request->username;
+
+              auth_result = cupsDoAuthentication (request->http, "POST", request->resource);
+
+              if (cups_password != NULL)
+                return;
+
+              if (request->password != NULL)
+                {
+                  memset (request->password, 0, strlen (request->password));
+                  g_free (request->password);
+                  request->password = NULL;
+                }
+
+              request->password_state = GTK_CUPS_PASSWORD_APPLIED;
+            }
+        }
+
+      if (auth_result ||
+          httpReconnect (request->http))
+        {
+          /* if the password has been used, reset password_state
+           * so that we ask for a new one next time around
+           */ 
+          if (cups_password == NULL)
+            request->password_state = GTK_CUPS_PASSWORD_NONE;
+
+          request->state = GTK_CUPS_POST_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+          gtk_cups_result_set_error (request->result, 
+                                     GTK_CUPS_ERROR_AUTH,
+                                     0,
+                                     0,
+                                     "Not authorized");
+          return;
+        }
       
-      /* TODO: create a not implemented error code */
-      gtk_cups_result_set_error (request->result, 
-                                 GTK_CUPS_ERROR_GENERAL,
-                                 0,
-                                 0,
-                                 "Can't prompt for authorization");
-      return;
+      if (request->data_io != NULL)
+        g_io_channel_seek_position (request->data_io, 0, G_SEEK_SET, NULL);
+
+      request->state = GTK_CUPS_POST_CONNECT;
+      request->poll_state = GTK_CUPS_HTTP_WRITE;
     }
   else if (http_status == HTTP_ERROR)
     {
@@ -883,7 +1063,7 @@
                                      http_errno, 
                                      "HTTP Error in POST %s", 
                                      g_strerror (http_errno));
-         request->poll_state = GTK_CUPS_HTTP_IDLE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
  
           httpFlush (request->http); 
           return;
@@ -975,9 +1155,13 @@
     }
 
   httpClearFields (request->http);
+#ifdef HAVE_HTTPGETAUTHSTRING
+  httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString (request->http));
+#else
 #ifdef HAVE_HTTP_AUTHSTRING
   httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
 #endif
+#endif
 
   if (httpGet (request->http, request->resource))
     {
@@ -997,6 +1181,9 @@
       request->attempts++;
       return;    
     }
+
+  if (httpCheck (request->http))
+    request->last_status = httpUpdate (request->http);
         
   request->attempts = 0;
 
@@ -1024,18 +1211,90 @@
     }
   else if (http_status == HTTP_UNAUTHORIZED)
     {
-      /* TODO: callout for auth */
-      g_warning ("NOT IMPLEMENTED: We need to prompt for authorization in a non blocking manner");
-      request->state = GTK_CUPS_GET_DONE;
-      request->poll_state = GTK_CUPS_HTTP_IDLE;
+      int auth_result = -1;
+      httpFlush (request->http);
 
-      /* TODO: should add a status or error code for not implemented */ 
-      gtk_cups_result_set_error (request->result, 
-                                 GTK_CUPS_ERROR_GENERAL,
-                                 0,
-                                 0,
-                                 "Can't prompt for authorization");
-      return;
+      if (request->password_state == GTK_CUPS_PASSWORD_APPLIED)
+        {
+          request->password_state = GTK_CUPS_PASSWORD_NOT_VALID;
+          request->state = GTK_CUPS_GET_AUTH;
+          request->need_password = TRUE;
+
+          return;
+        }
+
+      /* Negotiate */
+      if (strncmp (httpGetField (request->http, HTTP_FIELD_WWW_AUTHENTICATE), "Negotiate", 9) == 0)
+        {
+          auth_result = cupsDoAuthentication (request->http, "GET", request->resource);
+        }
+      /* Basic, BasicDigest, Digest and PeerCred */
+      else
+        {
+          if (request->password_state == GTK_CUPS_PASSWORD_NONE)
+            {
+              cups_password = g_strdup("");
+              cups_username = request->username;
+              cupsSetPasswordCB (passwordCB);
+
+              /* This call success for PeerCred authentication */
+              auth_result = cupsDoAuthentication (request->http, "GET", request->resource);
+
+              if (auth_result != 0)
+                {
+                  /* move to AUTH state to let the backend
+                   * ask for a password
+                   */
+                  request->state = GTK_CUPS_GET_AUTH;
+                  request->need_password = TRUE;
+
+                  return;
+                }
+            }
+          else
+            {
+              cups_password = request->password;
+              cups_username = request->username;
+
+              auth_result = cupsDoAuthentication (request->http, "GET", request->resource);
+
+              if (cups_password != NULL)
+                return;
+
+              if (request->password != NULL)
+                {
+                  memset (request->password, 0, strlen (request->password));
+                  g_free (request->password);
+                  request->password = NULL;
+                }
+
+              request->password_state = GTK_CUPS_PASSWORD_APPLIED;
+            }
+        }
+
+      if (auth_result ||
+          httpReconnect (request->http))
+        {
+          /* if the password has been used, reset password_state
+           * so that we ask for a new one next time around
+           */
+          if (cups_password == NULL)
+            request->password_state = GTK_CUPS_PASSWORD_NONE;
+
+          request->state = GTK_CUPS_GET_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+          gtk_cups_result_set_error (request->result, 
+                                     GTK_CUPS_ERROR_AUTH,
+                                     0,
+                                     0,
+                                     "Not authorized");
+          return;
+        }
+
+      request->state = GTK_CUPS_GET_SEND;
+      request->last_status = HTTP_CONTINUE;
+
+     return;
     }
   else if (http_status == HTTP_UPGRADE_REQUIRED)
     {
@@ -1043,7 +1302,7 @@
       httpFlush (request->http);
 
       cupsSetEncryption (HTTP_ENCRYPT_REQUIRED);
-      request->state = GTK_CUPS_POST_CONNECT;
+      request->state = GTK_CUPS_GET_CONNECT;
 
       /* Reconnect... */
       httpReconnect (request->http);
@@ -1143,7 +1402,7 @@
 
   if (io_status == G_IO_STATUS_ERROR)
     {
-      request->state = GTK_CUPS_POST_DONE;
+      request->state = GTK_CUPS_GET_DONE;
       request->poll_state = GTK_CUPS_HTTP_IDLE;
     
       gtk_cups_result_set_error (request->result,
Index: modules/printbackends/cups/gtkprintbackendcups.c
===================================================================
--- modules/printbackends/cups/gtkprintbackendcups.c	(revision 22560)
+++ modules/printbackends/cups/gtkprintbackendcups.c	(working copy)
@@ -118,6 +118,11 @@
   char  *default_cover_before;
   char  *default_cover_after;
   int    number_of_covers;
+
+  GList *requests;
+  GHashTable *auth;
+  gchar      *username;
+  gboolean authentication_lock;
 };
 
 static GObjectClass *backend_parent_class;
@@ -176,7 +181,14 @@
 								    gdouble                            height,
 								    GIOChannel                        *cache_io);
 
+static void                 gtk_print_backend_cups_set_password    (GtkPrintBackend *backend, 
+                                                                    const gchar     *hostname,
+                                                                    const gchar     *username,
+                                                                    const gchar     *password);
 
+void                        overwrite_and_free                      (gpointer data);
+static gboolean             is_address_local                        (const gchar *address);
+
 static void
 gtk_print_backend_cups_register_type (GTypeModule *module)
 {
@@ -271,6 +283,7 @@
   backend_class->printer_get_default_page_size = cups_printer_get_default_page_size;
   backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
   backend_class->printer_get_capabilities = cups_printer_get_capabilities;
+  backend_class->set_password = gtk_print_backend_cups_set_password;
 }
 
 static cairo_status_t
@@ -511,12 +524,13 @@
   cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
   settings = gtk_print_job_get_settings (job);
 
-  request = gtk_cups_request_new (NULL,
-                                  GTK_CUPS_POST,
-                                  IPP_PRINT_JOB,
-				  data_io,
-				  NULL, 
-				  cups_printer->device_uri);
+  request = gtk_cups_request_new_with_username (NULL,
+                                                GTK_CUPS_POST,
+                                                IPP_PRINT_JOB,
+				                data_io,
+				                NULL, 
+				                cups_printer->device_uri,
+				                GTK_PRINT_BACKEND_CUPS (print_backend)->username);
 
 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
   httpAssembleURIf (HTTP_URI_CODING_ALL,
@@ -561,7 +575,17 @@
                         (GDestroyNotify)cups_free_print_stream_data);
 }
 
+void overwrite_and_free (gpointer data)
+{
+  gchar *password = (gchar *) data;
 
+  if (password != NULL)
+    {
+      memset (password, 0, strlen (password));
+      g_free (password);
+    }
+}
+
 static void
 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
 {
@@ -569,6 +593,10 @@
   backend_cups->got_default_printer = FALSE;  
   backend_cups->list_printers_pending = FALSE;
 
+  backend_cups->requests = NULL;
+  backend_cups->auth = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, overwrite_and_free);
+  backend_cups->authentication_lock = FALSE;
+
   backend_cups->covers = NULL;
   backend_cups->default_cover_before = NULL;
   backend_cups->default_cover_after = NULL;
@@ -577,6 +605,8 @@
   backend_cups->default_printer_poll = 0;
   backend_cups->cups_connection_test = NULL;
 
+  backend_cups->username = NULL;
+
   cups_get_local_default_printer (backend_cups);
 }
 
@@ -602,6 +632,10 @@
   gtk_cups_connection_test_free (backend_cups->cups_connection_test);
   backend_cups->cups_connection_test = NULL;
 
+  g_hash_table_destroy (backend_cups->auth);
+
+  g_free (backend_cups->username);
+
   backend_parent_class->finalize (object);
 }
 
@@ -626,8 +660,137 @@
   backend_parent_class->dispose (object);
 }
 
+static gboolean
+is_address_local (const gchar *address)
+{
+  if (address[0] == '/' ||
+      strcmp (address, "127.0.0.1") == 0 ||
+      strcmp (address, "[::1]") == 0)
+    return TRUE;
+  else
+    return FALSE;
+}
 
+static void
+gtk_print_backend_cups_set_password (GtkPrintBackend *backend,
+                                     const gchar     *hostname,
+                                     const gchar     *username, 
+                                     const gchar     *password)
+{
+  GtkPrintBackendCups *cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
+  GList *l;
+  char   dispatch_hostname[HTTP_MAX_URI];
+  gchar *key;
+
+  key = g_strconcat (username, "@", hostname, NULL);
+  g_hash_table_insert (cups_backend->auth, key, g_strdup (password));
+
+  g_free (cups_backend->username);
+  cups_backend->username = g_strdup (username);
+
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS backend: storing password for %s\n", key));
+
+  for (l = cups_backend->requests; l; l = l->next)
+    {
+      GtkPrintCupsDispatchWatch *dispatch = l->data;
+
+      httpGetHostname (dispatch->request->http, dispatch_hostname, sizeof (dispatch_hostname));
+      if (is_address_local (dispatch_hostname))
+        strcpy (dispatch_hostname, "localhost");
+
+      if (strcmp (hostname, dispatch_hostname) == 0) 
+        {
+          overwrite_and_free (dispatch->request->password);
+          dispatch->request->password = g_strdup (password);
+          g_free (dispatch->request->username);
+          dispatch->request->username = g_strdup (username);
+          dispatch->request->password_state = GTK_CUPS_PASSWORD_HAS;
+          dispatch->backend->authentication_lock = FALSE;
+        }
+    }
+}
+
 static gboolean
+request_password (gpointer data)
+{
+  GtkPrintCupsDispatchWatch *dispatch = data;
+  const gchar               *username;
+  gchar                     *password;
+  gchar                     *prompt;
+  gchar                     *key;
+  char                       hostname[HTTP_MAX_URI];
+
+  if (dispatch->backend->authentication_lock)
+    return FALSE;
+
+  httpGetHostname (dispatch->request->http, hostname, sizeof (hostname));
+  if (is_address_local (hostname))
+    strcpy (hostname, "localhost");
+
+  if (dispatch->backend->username != NULL)
+    username = dispatch->backend->username;
+  else
+    username = cupsUser ();
+
+  key = g_strconcat (username, "@", hostname, NULL);
+  password = g_hash_table_lookup (dispatch->backend->auth, key);
+
+  if (password && dispatch->request->password_state != GTK_CUPS_PASSWORD_NOT_VALID)
+    {
+      GTK_NOTE (PRINTING,
+                g_print ("CUPS backend: using stored password for %s\n", key));
+
+      overwrite_and_free (dispatch->request->password);
+      dispatch->request->password = g_strdup (password);
+      g_free (dispatch->request->username);
+      dispatch->request->username = g_strdup (username);
+      dispatch->request->password_state = GTK_CUPS_PASSWORD_HAS;
+    }
+  else
+    {
+      if (dispatch->request->password_state == GTK_CUPS_PASSWORD_NOT_VALID)
+        g_hash_table_remove (dispatch->backend->auth, key);
+
+      dispatch->request->password_state = GTK_CUPS_PASSWORD_REQUESTED;
+
+      dispatch->backend->authentication_lock = TRUE;
+
+      switch (dispatch->request->ipp_request->request.op.operation_id)
+        {
+          case 0:
+            prompt = g_strdup_printf ( _("Authentication is required to get a file from %s"), hostname);
+            break;
+          case IPP_PRINT_JOB:
+            prompt = g_strdup_printf ( _("Authentication is required to print a job on %s"), hostname);
+            break;
+          case IPP_GET_JOB_ATTRIBUTES:
+            prompt = g_strdup ( _("Authentication is required to get attributes of a job"));
+            break;
+          case IPP_GET_PRINTER_ATTRIBUTES:
+            prompt = g_strdup ( _("Authentication is required to get attributes of a printer"));
+            break;
+          case CUPS_GET_DEFAULT:
+            prompt = g_strdup_printf ( _("Authentication is required to get default printer of %s"), hostname);
+            break;
+          case CUPS_GET_PRINTERS:
+            prompt = g_strdup_printf ( _("Authentication is required to get printers from %s"), hostname);
+            break;
+          default:
+            prompt = g_strdup_printf ( _("Authentication is required on %s"), hostname);
+            break;
+        }
+
+      g_signal_emit_by_name (dispatch->backend, "request-password", 
+                             hostname, username, prompt);
+    }
+
+  g_free (key);
+
+  return FALSE;
+}
+
+static gboolean
 cups_dispatch_watch_check (GSource *source)
 {
   GtkPrintCupsDispatchWatch *dispatch;
@@ -665,7 +828,7 @@
 #endif
     }
     
-  if (poll_state != GTK_CUPS_HTTP_IDLE)  
+  if (poll_state != GTK_CUPS_HTTP_IDLE && !dispatch->request->need_password)
     if (!(dispatch->data_poll->revents & dispatch->data_poll->events)) 
        return FALSE;
   
@@ -676,6 +839,13 @@
       g_free (dispatch->data_poll);
       dispatch->data_poll = NULL;
     }
+
+  if (dispatch->request->need_password && dispatch->request->password_state != GTK_CUPS_PASSWORD_REQUESTED)
+    {
+      dispatch->request->need_password = FALSE;
+      g_idle_add (request_password, dispatch);
+      result = FALSE;
+    }
   
   return result;
 }
@@ -735,12 +905,39 @@
 cups_dispatch_watch_finalize (GSource *source)
 {
   GtkPrintCupsDispatchWatch *dispatch;
+  GtkCupsResult *result;
 
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
 
   dispatch = (GtkPrintCupsDispatchWatch *) source;
 
+  result = gtk_cups_request_get_result (dispatch->request);
+  if (gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_AUTH)
+    {
+      const gchar *username;
+      gchar        hostname[HTTP_MAX_URI];
+      gchar       *key;
+    
+      httpGetHostname (dispatch->request->http, hostname, sizeof (hostname));
+      if (is_address_local (hostname))
+        strcpy (hostname, "localhost");
+
+      if (dispatch->backend->username != NULL)
+        username = dispatch->backend->username;
+      else
+        username = cupsUser ();
+
+      key = g_strconcat (username, "@", hostname, NULL);
+      GTK_NOTE (PRINTING,
+                g_print ("CUPS backend: removing stored password for %s\n", key));
+      g_hash_table_remove (dispatch->backend->auth, key);
+      g_free (key);
+      
+      if (dispatch->backend)
+        dispatch->backend->authentication_lock = FALSE;
+    }
+
   gtk_cups_request_free (dispatch->request);
 
   if (dispatch->backend)
@@ -754,6 +951,10 @@
        * of print backends. See _gtk_print_backend_create for the
        * disabling.
        */
+
+      dispatch->backend->requests = g_list_remove (dispatch->backend->requests, dispatch);
+
+      
       g_object_unref (dispatch->backend);
       dispatch->backend = NULL;
     }
@@ -788,6 +989,8 @@
   dispatch->backend = g_object_ref (print_backend);
   dispatch->data_poll = NULL;
 
+  print_backend->requests = g_list_prepend (print_backend->requests, dispatch);
+
   g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
 
   g_source_attach ((GSource *) dispatch, NULL);
@@ -890,12 +1093,13 @@
       "job-sheets-default"
     };
 
-  request = gtk_cups_request_new (NULL,
-                                  GTK_CUPS_POST,
-                                  IPP_GET_PRINTER_ATTRIBUTES,
-				  NULL,
-				  NULL,
-				  NULL);
+  request = gtk_cups_request_new_with_username (NULL,
+                                                GTK_CUPS_POST,
+                                                IPP_GET_PRINTER_ATTRIBUTES,
+                                                NULL,
+                                                NULL,
+                                                NULL,
+                                                print_backend->username);
 
   printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
                                   printer_name);
@@ -1029,12 +1233,13 @@
   GtkCupsRequest *request;
   gchar *job_uri;
 
-  request = gtk_cups_request_new (NULL,
-                                  GTK_CUPS_POST,
-                                  IPP_GET_JOB_ATTRIBUTES,
-				  NULL,
-				  NULL,
-				  NULL);
+  request = gtk_cups_request_new_with_username (NULL,
+                                                GTK_CUPS_POST,
+                                                IPP_GET_JOB_ATTRIBUTES,
+                                                NULL,
+                                                NULL,
+                                                NULL,
+                                                data->print_backend->username);
 
   job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
@@ -1121,9 +1326,20 @@
   if (gtk_cups_result_is_error (result))
     {
       GTK_NOTE (PRINTING, 
-                g_warning ("CUPS Backend: Error getting printer list: %s", 
-        	           gtk_cups_result_get_error_string (result)));
+                g_warning ("CUPS Backend: Error getting printer list: %s %d %d", 
+                           gtk_cups_result_get_error_string (result),
+                           gtk_cups_result_get_error_type (result),
+                           gtk_cups_result_get_error_code (result)));
 
+      if (gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_AUTH &&
+          gtk_cups_result_get_error_code (result) == 1)
+        {
+          /* Canceled by user, stop popping up more password dialogs */
+          if (cups_backend->list_printers_poll > 0)
+            g_source_remove (cups_backend->list_printers_poll);
+          cups_backend->list_printers_poll = 0;
+        }
+
       goto done;
     }
   
@@ -1609,12 +1825,13 @@
 
   cups_backend->list_printers_pending = TRUE;
 
-  request = gtk_cups_request_new (NULL,
-                                  GTK_CUPS_POST,
-                                  CUPS_GET_PRINTERS,
-				  NULL,
-				  NULL,
-				  NULL);
+  request = gtk_cups_request_new_with_username (NULL,
+                                                GTK_CUPS_POST,
+                                                CUPS_GET_PRINTERS,
+                                                NULL,
+                                                NULL,
+                                                NULL,
+                                                cups_backend->username);
 
   gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
 				    "requested-attributes", G_N_ELEMENTS (pattrs),
@@ -1776,28 +1993,30 @@
   resource = g_strdup_printf ("/printers/%s.ppd", 
                               gtk_printer_cups_get_ppd_name (GTK_PRINTER_CUPS (printer)));
 
-  request = gtk_cups_request_new (data->http,
-                                  GTK_CUPS_GET,
-				  0,
-                                  data->ppd_io,
-				  cups_printer->hostname,
-				  resource);
+  print_backend = gtk_printer_get_backend (printer);
 
+  request = gtk_cups_request_new_with_username (data->http,
+                                                GTK_CUPS_GET,
+                                                0,
+                                                data->ppd_io,
+                                                cups_printer->hostname,
+                                                resource,
+                                                GTK_PRINT_BACKEND_CUPS (print_backend)->username);
+
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename));
 
-  g_free (resource);
-  g_free (ppd_filename);
 
   cups_printer->reading_ppd = TRUE;
 
-  print_backend = gtk_printer_get_backend (printer);
-
   cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
                         request,
                         (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
                         data,
                         (GDestroyNotify)get_ppd_data_free);
+
+  g_free (resource);
+  g_free (ppd_filename);
 }
 
 /* Ordering matters for default preference */
@@ -2018,6 +2237,20 @@
 
   GDK_THREADS_ENTER ();
 
+  if (gtk_cups_result_is_error (result))
+    {
+      if (gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_AUTH &&
+          gtk_cups_result_get_error_code (result) == 1)
+        {
+          /* Canceled by user, stop popping up more password dialogs */
+          if (print_backend->list_printers_poll > 0)
+            g_source_remove (print_backend->list_printers_poll);
+          print_backend->list_printers_poll = 0;
+        }
+
+      return;
+    }
+
   response = gtk_cups_result_get_response (result);
   
   if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
@@ -2056,12 +2289,13 @@
   if (state == GTK_CUPS_CONNECTION_IN_PROGRESS || state == GTK_CUPS_CONNECTION_NOT_AVAILABLE)
     return TRUE;
 
-  request = gtk_cups_request_new (NULL,
-                                  GTK_CUPS_POST,
-                                  CUPS_GET_DEFAULT,
-				  NULL,
-				  NULL,
-				  NULL);
+  request = gtk_cups_request_new_with_username (NULL,
+                                                GTK_CUPS_POST,
+                                                CUPS_GET_DEFAULT,
+                                                NULL,
+                                                NULL,
+                                                NULL,
+                                                print_backend->username);
   
   cups_request_execute (print_backend,
                         request,
Index: modules/printbackends/cups/gtkcupsutils.h
===================================================================
--- modules/printbackends/cups/gtkcupsutils.h	(revision 22560)
+++ modules/printbackends/cups/gtkcupsutils.h	(working copy)
@@ -37,6 +37,7 @@
   GTK_CUPS_ERROR_HTTP,
   GTK_CUPS_ERROR_IPP,
   GTK_CUPS_ERROR_IO,
+  GTK_CUPS_ERROR_AUTH,
   GTK_CUPS_ERROR_GENERAL
 } GtkCupsErrorType;
 
@@ -66,6 +67,15 @@
   GTK_CUPS_CONNECTION_IN_PROGRESS  
 } GtkCupsConnectionState;
 
+typedef enum
+{
+  GTK_CUPS_PASSWORD_NONE,
+  GTK_CUPS_PASSWORD_REQUESTED,
+  GTK_CUPS_PASSWORD_HAS,
+  GTK_CUPS_PASSWORD_APPLIED,
+  GTK_CUPS_PASSWORD_NOT_VALID
+} GtkCupsPasswordState;
+
 struct _GtkCupsRequest 
 {
   GtkCupsRequestType type;
@@ -84,7 +94,12 @@
   gint state;
   GtkCupsPollState poll_state;
 
-  gint own_http : 1; 
+  gchar *password;
+  gchar *username;
+
+  gint own_http : 1;
+  gint need_password : 1;
+  GtkCupsPasswordState password_state;
 };
 
 struct _GtkCupsConnectionTest
@@ -108,6 +123,7 @@
   GTK_CUPS_POST_WRITE_REQUEST,
   GTK_CUPS_POST_WRITE_DATA,
   GTK_CUPS_POST_CHECK,
+  GTK_CUPS_POST_AUTH,
   GTK_CUPS_POST_READ_RESPONSE,
   GTK_CUPS_POST_DONE = GTK_CUPS_REQUEST_DONE
 };
@@ -118,10 +134,18 @@
   GTK_CUPS_GET_CONNECT = GTK_CUPS_REQUEST_START,
   GTK_CUPS_GET_SEND,
   GTK_CUPS_GET_CHECK,
+  GTK_CUPS_GET_AUTH,
   GTK_CUPS_GET_READ_DATA,
   GTK_CUPS_GET_DONE = GTK_CUPS_REQUEST_DONE
 };
 
+GtkCupsRequest        * gtk_cups_request_new_with_username (http_t             *connection,
+							    GtkCupsRequestType  req_type,
+							    gint                operation_id,
+							    GIOChannel         *data_io,
+							    const char         *server,
+							    const char         *resource,
+							    const char         *username);
 GtkCupsRequest        * gtk_cups_request_new               (http_t             *connection,
 							    GtkCupsRequestType  req_type,
 							    gint                operation_id,
