1/* client.c --- OPENID20 mechanism, client side.
2 * Copyright (C) 2011-2012 Simon Josefsson
3 *
4 * This file is part of GNU SASL Library.
5 *
6 * GNU SASL Library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * GNU SASL Library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with GNU SASL Library; if not, write to the Free
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27/* Get specification. */
28#include "openid20.h"
29
30/* Get strdup, strlen. */
31#include <string.h>
32
33/* Get calloc, free. */
34#include <stdlib.h>
35
36/* Get bool. */
37#include <stdbool.h>
38
39/* Get _gsasl_gs2_generate_header. */
40#include "mechtools.h"
41
42struct openid20_client_state
43{
44 int step;
45};
46
47int
48_gsasl_openid20_client_start (Gsasl_session * sctx, void **mech_data)
49{
50 struct openid20_client_state *state;
51
52 state = (struct openid20_client_state *) calloc (sizeof (*state), 1);
53 if (state == NULL)
54 return GSASL_MALLOC_ERROR;
55
56 *mech_data = state;
57
58 return GSASL_OK;
59}
60
61int
62_gsasl_openid20_client_step (Gsasl_session * sctx,
63 void *mech_data,
64 const char *input, size_t input_len,
65 char **output, size_t * output_len)
66{
67 struct openid20_client_state *state = mech_data;
68 int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
69
70 switch (state->step)
71 {
72 case 0:
73 {
74 const char *authzid = gsasl_property_get (sctx, GSASL_AUTHZID);
75 const char *authid = gsasl_property_get (sctx, GSASL_AUTHID);
76
77 if (!authid || !*authid)
78 return GSASL_NO_AUTHID;
79
80 res = _gsasl_gs2_generate_header (false, 'n', NULL, authzid,
81 strlen (authid), authid,
82 output, output_len);
83 if (res != GSASL_OK)
84 return res;
85
86 res = GSASL_NEEDS_MORE;
87 state->step++;
88 }
89 break;
90
91 case 1:
92 {
93 gsasl_property_set_raw (sctx, GSASL_OPENID20_REDIRECT_URL,
94 input, input_len);
95
96 res = gsasl_callback (NULL, sctx,
97 GSASL_OPENID20_AUTHENTICATE_IN_BROWSER);
98 if (res != GSASL_OK)
99 return res;
100
101 *output_len = 1;
102 *output = strdup ("=");
103 if (!*output)
104 return GSASL_MALLOC_ERROR;
105
106 res = GSASL_OK;
107 state->step++;
108 }
109 break;
110
111 /* This step is optional. The server could have approved
112 authentication already. Alternatively, it wanted to send
113 some SREGs or error data and we end up here. */
114 case 2:
115 {
116 gsasl_property_set_raw (sctx, GSASL_OPENID20_OUTCOME_DATA,
117 input, input_len);
118
119 /* In the case of failures, the response MUST follow this
120 syntax:
121
122 outcome_data = "openid.error" "=" sreg_val *( "," sregp_avp )
123
124 [RFC4422] Section 3.6 explicitly prohibits additional information in
125 an unsuccessful authentication outcome. Therefore, the openid.error
126 and openid.error_code are to be sent as an additional challenge in
127 the event of an unsuccessful outcome. In this case, as the protocol
128 is lock step, the client will follow with an additional exchange
129 containing "=", after which the server will respond with an
130 application-level outcome.
131 */
132
133#define ERR_PREFIX "openid.error="
134 if (input_len > strlen (ERR_PREFIX)
135 && strncmp (ERR_PREFIX, input, strlen (ERR_PREFIX)) == 0)
136 {
137 *output_len = 1;
138 *output = strdup ("=");
139 if (!*output)
140 return GSASL_MALLOC_ERROR;
141
142 res = GSASL_NEEDS_MORE;
143 }
144 else
145 {
146 *output_len = 0;
147 *output = NULL;
148
149 res = GSASL_OK;
150 }
151
152 state->step++;
153 }
154 break;
155
156 default:
157 break;
158 }
159
160 return res;
161}
162
163void
164_gsasl_openid20_client_finish (Gsasl_session * sctx, void *mech_data)
165{
166 struct openid20_client_state *state = mech_data;
167
168 if (!state)
169 return;
170
171 free (state);
172}
173