gsasl  1.8.0
openid20/client.c
Go to the documentation of this file.
00001 /* client.c --- OPENID20 mechanism, client side.
00002  * Copyright (C) 2011-2012 Simon Josefsson
00003  *
00004  * This file is part of GNU SASL Library.
00005  *
00006  * GNU SASL Library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public License
00008  * as published by the Free Software Foundation; either version 2.1 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * GNU SASL Library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with GNU SASL Library; if not, write to the Free
00018  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 /* Get specification. */
00028 #include "openid20.h"
00029 
00030 /* Get strdup, strlen. */
00031 #include <string.h>
00032 
00033 /* Get calloc, free. */
00034 #include <stdlib.h>
00035 
00036 /* Get bool. */
00037 #include <stdbool.h>
00038 
00039 /* Get _gsasl_gs2_generate_header. */
00040 #include "mechtools.h"
00041 
00042 struct openid20_client_state
00043 {
00044   int step;
00045 };
00046 
00047 int
00048 _gsasl_openid20_client_start (Gsasl_session * sctx, void **mech_data)
00049 {
00050   struct openid20_client_state *state;
00051 
00052   state = (struct openid20_client_state *) calloc (sizeof (*state), 1);
00053   if (state == NULL)
00054     return GSASL_MALLOC_ERROR;
00055 
00056   *mech_data = state;
00057 
00058   return GSASL_OK;
00059 }
00060 
00061 int
00062 _gsasl_openid20_client_step (Gsasl_session * sctx,
00063                              void *mech_data,
00064                              const char *input, size_t input_len,
00065                              char **output, size_t * output_len)
00066 {
00067   struct openid20_client_state *state = mech_data;
00068   int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00069 
00070   switch (state->step)
00071     {
00072     case 0:
00073       {
00074         const char *authzid = gsasl_property_get (sctx, GSASL_AUTHZID);
00075         const char *authid = gsasl_property_get (sctx, GSASL_AUTHID);
00076 
00077         if (!authid || !*authid)
00078           return GSASL_NO_AUTHID;
00079 
00080         res = _gsasl_gs2_generate_header (false, 'n', NULL, authzid,
00081                                           strlen (authid), authid,
00082                                           output, output_len);
00083         if (res != GSASL_OK)
00084           return res;
00085 
00086         res = GSASL_NEEDS_MORE;
00087         state->step++;
00088       }
00089       break;
00090 
00091     case 1:
00092       {
00093         gsasl_property_set_raw (sctx, GSASL_OPENID20_REDIRECT_URL,
00094                                 input, input_len);
00095 
00096         res = gsasl_callback (NULL, sctx,
00097                               GSASL_OPENID20_AUTHENTICATE_IN_BROWSER);
00098         if (res != GSASL_OK)
00099           return res;
00100 
00101         *output_len = 1;
00102         *output = strdup ("=");
00103         if (!*output)
00104           return GSASL_MALLOC_ERROR;
00105 
00106         res = GSASL_OK;
00107         state->step++;
00108       }
00109       break;
00110 
00111       /* This step is optional.  The server could have approved
00112          authentication already.  Alternatively, it wanted to send
00113          some SREGs or error data and we end up here. */
00114     case 2:
00115       {
00116         gsasl_property_set_raw (sctx, GSASL_OPENID20_OUTCOME_DATA,
00117                                 input, input_len);
00118 
00119         /* In the case of failures, the response MUST follow this
00120            syntax:
00121 
00122            outcome_data = "openid.error" "=" sreg_val *( "," sregp_avp )
00123 
00124            [RFC4422] Section 3.6 explicitly prohibits additional information in
00125            an unsuccessful authentication outcome.  Therefore, the openid.error
00126            and openid.error_code are to be sent as an additional challenge in
00127            the event of an unsuccessful outcome.  In this case, as the protocol
00128            is lock step,  the client will follow with an additional exchange
00129            containing "=", after which the server will respond with an
00130            application-level outcome.
00131          */
00132 
00133 #define ERR_PREFIX "openid.error="
00134         if (input_len > strlen (ERR_PREFIX)
00135             && strncmp (ERR_PREFIX, input, strlen (ERR_PREFIX)) == 0)
00136           {
00137             *output_len = 1;
00138             *output = strdup ("=");
00139             if (!*output)
00140               return GSASL_MALLOC_ERROR;
00141 
00142             res = GSASL_NEEDS_MORE;
00143           }
00144         else
00145           {
00146             *output_len = 0;
00147             *output = NULL;
00148 
00149             res = GSASL_OK;
00150           }
00151 
00152         state->step++;
00153       }
00154       break;
00155 
00156     default:
00157       break;
00158     }
00159 
00160   return res;
00161 }
00162 
00163 void
00164 _gsasl_openid20_client_finish (Gsasl_session * sctx, void *mech_data)
00165 {
00166   struct openid20_client_state *state = mech_data;
00167 
00168   if (!state)
00169     return;
00170 
00171   free (state);
00172 }