I#27 - [IMAPx] Ignore DavMail's CR/LF in BODYSTRUCTURE response
[evolution-data-server.git] / src / libedataserver / e-soup-auth-bearer.c
blob8d1efa82a2e1d59ec5ed9ff6c7cd566db32f6f67
1 /*
2 * e-soup-auth-bearer.c
4 * This library is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * SECTION: e-soup-auth-bearer
20 * @include: libedataserver/libedataserver.h
21 * @short_description: OAuth 2.0 support for libsoup
23 * #ESoupAuthBearer adds libsoup support for the use of bearer tokens in
24 * HTTP requests to access OAuth 2.0 protected resources, as defined in
25 * <ulink url="http://tools.ietf.org/html/rfc6750">RFC 6750</ulink>.
27 * An #EBackend should integrate #ESoupAuthBearer first by adding it as a
28 * feature to a #SoupSession's #SoupAuthManager, then from a #SoupSession
29 * #SoupSession::authenticate handler call e_source_get_oauth2_access_token()
30 * and pass the results to e_soup_auth_bearer_set_access_token().
31 **/
33 #include "evolution-data-server-config.h"
35 #include "e-soup-auth-bearer.h"
37 #include <time.h>
39 #define E_SOUP_AUTH_BEARER_GET_PRIVATE(obj) \
40 (G_TYPE_INSTANCE_GET_PRIVATE \
41 ((obj), E_TYPE_SOUP_AUTH_BEARER, ESoupAuthBearerPrivate))
43 #define AUTH_STRENGTH 1
45 #define EXPIRY_INVALID ((time_t) -1)
47 struct _ESoupAuthBearerPrivate {
48 gchar *access_token;
49 time_t expiry;
52 G_DEFINE_TYPE (
53 ESoupAuthBearer,
54 e_soup_auth_bearer,
55 SOUP_TYPE_AUTH)
57 static void
58 e_soup_auth_bearer_finalize (GObject *object)
60 ESoupAuthBearerPrivate *priv;
62 priv = E_SOUP_AUTH_BEARER_GET_PRIVATE (object);
64 g_free (priv->access_token);
66 /* Chain up to parent's finalize() method. */
67 G_OBJECT_CLASS (e_soup_auth_bearer_parent_class)->finalize (object);
70 static gboolean
71 e_soup_auth_bearer_update (SoupAuth *auth,
72 SoupMessage *message,
73 GHashTable *auth_header)
75 if (message && message->status_code == SOUP_STATUS_UNAUTHORIZED) {
76 ESoupAuthBearer *bearer;
78 g_return_val_if_fail (E_IS_SOUP_AUTH_BEARER (auth), FALSE);
80 bearer = E_SOUP_AUTH_BEARER (auth);
82 /* Expire the token, it's likely to be invalid. */
83 bearer->priv->expiry = EXPIRY_INVALID;
85 return FALSE;
88 return TRUE;
91 static GSList *
92 e_soup_auth_bearer_get_protection_space (SoupAuth *auth,
93 SoupURI *source_uri)
95 /* XXX Not sure what to do here. Need to return something. */
97 return g_slist_prepend (NULL, g_strdup (""));
100 static gboolean
101 e_soup_auth_bearer_is_authenticated (SoupAuth *auth)
103 ESoupAuthBearer *bearer;
104 gboolean authenticated = FALSE;
106 bearer = E_SOUP_AUTH_BEARER (auth);
108 if (!e_soup_auth_bearer_is_expired (bearer))
109 authenticated = (bearer->priv->access_token != NULL);
111 return authenticated;
114 static gchar *
115 e_soup_auth_bearer_get_authorization (SoupAuth *auth,
116 SoupMessage *message)
118 ESoupAuthBearer *bearer;
120 bearer = E_SOUP_AUTH_BEARER (auth);
122 return g_strdup_printf ("Bearer %s", bearer->priv->access_token);
125 static void
126 e_soup_auth_bearer_class_init (ESoupAuthBearerClass *class)
128 GObjectClass *object_class;
129 SoupAuthClass *auth_class;
131 g_type_class_add_private (class, sizeof (ESoupAuthBearerPrivate));
133 /* Keep the "e" prefix on private methods
134 * so we don't step on libsoup's namespace. */
136 object_class = G_OBJECT_CLASS (class);
137 object_class->finalize = e_soup_auth_bearer_finalize;
139 auth_class = SOUP_AUTH_CLASS (class);
140 auth_class->scheme_name = "Bearer";
141 auth_class->strength = AUTH_STRENGTH;
142 auth_class->update = e_soup_auth_bearer_update;
143 auth_class->get_protection_space = e_soup_auth_bearer_get_protection_space;
144 auth_class->is_authenticated = e_soup_auth_bearer_is_authenticated;
145 auth_class->get_authorization = e_soup_auth_bearer_get_authorization;
148 static void
149 e_soup_auth_bearer_init (ESoupAuthBearer *bearer)
151 bearer->priv = E_SOUP_AUTH_BEARER_GET_PRIVATE (bearer);
152 bearer->priv->expiry = EXPIRY_INVALID;
156 * e_soup_auth_bearer_set_access_token:
157 * @bearer: an #ESoupAuthBearer
158 * @access_token: an OAuth 2.0 access token
159 * @expires_in_seconds: expiry for @access_token, or 0 if unknown
161 * This function is analogous to soup_auth_authenticate() for "Basic" HTTP
162 * authentication, except it takes an OAuth 2.0 access token instead of a
163 * username and password.
165 * If @expires_in_seconds is greater than zero, soup_auth_is_authenticated()
166 * will return %FALSE after the given number of seconds have elapsed.
168 * Since: 3.10
170 void
171 e_soup_auth_bearer_set_access_token (ESoupAuthBearer *bearer,
172 const gchar *access_token,
173 gint expires_in_seconds)
175 gboolean was_authenticated;
176 gboolean now_authenticated;
178 g_return_if_fail (E_IS_SOUP_AUTH_BEARER (bearer));
180 was_authenticated = soup_auth_is_authenticated (SOUP_AUTH (bearer));
182 g_free (bearer->priv->access_token);
183 bearer->priv->access_token = g_strdup (access_token);
185 if (expires_in_seconds > 0)
186 bearer->priv->expiry = time (NULL) + expires_in_seconds - 1;
187 else
188 bearer->priv->expiry = EXPIRY_INVALID;
190 now_authenticated = soup_auth_is_authenticated (SOUP_AUTH (bearer));
192 if (was_authenticated != now_authenticated)
193 g_object_notify (
194 G_OBJECT (bearer),
195 SOUP_AUTH_IS_AUTHENTICATED);
199 * e_soup_auth_bearer_is_expired:
200 * @bearer: an #ESoupAuthBearer
202 * Returns: Whether the set token is expired. It is considered expired even
203 * if the e_soup_auth_bearer_set_access_token() was called set yet.
205 * Since: 3.24
207 gboolean
208 e_soup_auth_bearer_is_expired (ESoupAuthBearer *bearer)
210 gboolean expired = TRUE;
212 g_return_val_if_fail (E_IS_SOUP_AUTH_BEARER (bearer), TRUE);
214 if (bearer->priv->expiry != EXPIRY_INVALID)
215 expired = (bearer->priv->expiry <= time (NULL));
217 return expired;