1/* server.c --- SAML20 mechanism, server side.
2 * Copyright (C) 2010-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 "saml20.h"
29
30/* Get strdup, strlen. */
31#include <string.h>
32
33/* Get free. */
34#include <stdlib.h>
35
36/* Get _gsasl_parse_gs2_header. */
37#include "mechtools.h"
38
39struct saml20_server_state
40{
41 int step;
42};
43
44int
45_gsasl_saml20_server_start (Gsasl_session * sctx, void **mech_data)
46{
47 struct saml20_server_state *state;
48
49 state = (struct saml20_server_state *) calloc (sizeof (*state), 1);
50 if (state == NULL)
51 return GSASL_MALLOC_ERROR;
52
53 *mech_data = state;
54
55 return GSASL_OK;
56}
57
58int
59_gsasl_saml20_server_step (Gsasl_session * sctx,
60 void *mech_data,
61 const char *input, size_t input_len,
62 char **output, size_t * output_len)
63{
64 struct saml20_server_state *state = mech_data;
65 int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
66
67 *output_len = 0;
68 *output = NULL;
69
70 switch (state->step)
71 {
72 case 0:
73 {
74 const char *p;
75 char *authzid;
76 size_t headerlen;
77
78 if (input_len == 0)
79 return GSASL_NEEDS_MORE;
80
81 res = _gsasl_parse_gs2_header (input, input_len,
82 &authzid, &headerlen);
83 if (res != GSASL_OK)
84 return res;
85
86 if (authzid)
87 {
88 gsasl_property_set (sctx, GSASL_AUTHZID, authzid);
89 free (authzid);
90 }
91
92 input += headerlen;
93 input_len -= headerlen;
94
95 gsasl_property_set_raw (sctx, GSASL_SAML20_IDP_IDENTIFIER,
96 input, input_len);
97
98 p = gsasl_property_get (sctx, GSASL_SAML20_REDIRECT_URL);
99 if (!p || !*p)
100 return GSASL_NO_SAML20_REDIRECT_URL;
101
102 *output_len = strlen (p);
103 *output = malloc (*output_len);
104 if (!*output)
105 return GSASL_MALLOC_ERROR;
106
107 memcpy (*output, p, *output_len);
108
109 res = GSASL_NEEDS_MORE;
110 state->step++;
111 break;
112 }
113
114 case 1:
115 {
116 if (!(input_len == 1 && *input == '='))
117 return GSASL_MECHANISM_PARSE_ERROR;
118
119 res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_SAML20);
120 if (res != GSASL_OK)
121 return res;
122
123 *output = NULL;
124 *output_len = 0;
125
126 res = GSASL_OK;
127 state->step++;
128 break;
129 }
130
131 default:
132 break;
133 }
134
135 return res;
136}
137
138void
139_gsasl_saml20_server_finish (Gsasl_session * sctx, void *mech_data)
140{
141 struct saml20_server_state *state = mech_data;
142
143 if (!state)
144 return;
145
146 free (state);
147}
148