Skip to content

Commit aa64901

Browse files
committed
Merge branch 'development' of https://git01.codeplex.com/forks/tsone/casadev into development
2 parents 77ecc51 + 70939da commit aa64901

File tree

6 files changed

+133
-92
lines changed

6 files changed

+133
-92
lines changed

Release/include/cpprest/oauth2_handler.h

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -61,30 +61,39 @@ class oauth2_exception : public std::exception
6161
/// OAuth 2.0 configuration.
6262
///
6363
/// Encapsulates functionality for:
64-
/// - Authenticating requests with an access token.
65-
/// - Performing the OAuth 2.0 authorization code grant authorization flow.
66-
/// See: http://tools.ietf.org/html/rfc6749#section-4.1
64+
/// - Authenticating requests with an access token.
65+
/// - Performing the OAuth 2.0 authorization code grant authorization flow.
66+
/// See: http://tools.ietf.org/html/rfc6749#section-4.1
67+
/// - Performing the OAuth 2.0 implicit grant authorization flow.
68+
/// See: http://tools.ietf.org/html/rfc6749#section-4.2
6769
///
68-
/// Usage for authorization:
70+
/// Performing OAuth 2.0 authorization:
6971
/// 1. Set service and client/app parameters:
70-
/// - Client/app key & secret (as provided by the service).
71-
/// - The service authorization endpoint and token endpoint.
72-
/// - Your client/app redirect URI.
73-
/// - Set if bearer token is passed in query or header field (default: header).
74-
/// See: http://tools.ietf.org/html/rfc6750#section-2
75-
/// - If the service uses "non-standard" access token key, set it also (default: "access_token").
76-
/// 2. Open web browser with URI from build_authorization_uri().
77-
/// - The passed state string should be unique for this authorization session.
78-
/// 3. In the web browser, the resource owner clicks "Yes" to authorize your client/app.
79-
/// 4. To signal authorization, web browser is redirected to redirect_uri().
80-
/// 5. The redirect contains the authorization code and the state string.
81-
/// 6. Check the state string equals the one in step 2.
82-
/// 7. Pass the authorization code to fetch_token() to create a token fetch task.
72+
/// - Client/app key & secret (as provided by the service).
73+
/// - The service authorization endpoint and token endpoint.
74+
/// - Your client/app redirect URI.
75+
/// - Use set_state() to assign a unique state string for the authorization
76+
/// session (default: "").
77+
/// - If needed, use set_bearer_auth() to control bearer token passing in either
78+
/// query or header (default: header). See: http://tools.ietf.org/html/rfc6750#section-2
79+
/// - If needed, use set_access_token_key() to set "non-standard" access token
80+
/// key (default: "access_token").
81+
/// - If needed, use set_implicit_grant() to enable implicit grant flow.
82+
/// 2. Build authorization URI with build_authorization_uri() and open this in web browser/control.
83+
/// 3. The resource owner should then clicks "Yes" to authorize your client/app, and
84+
/// as a result the web browser/control is redirected to redirect_uri().
85+
/// 5. Capture the redirected URI either in web control or by HTTP listener.
86+
/// 6. Pass the redirected URI to token_from_redirected_uri() to obtain access token.
87+
/// - The method ensures redirected URI contains same state() as set in step 1.
88+
/// - In implicit_grant() is false, this will create HTTP request to fetch access token
89+
/// from the service. Otherwise access token is already included in the redirected URI.
8390
///
8491
/// Usage for issuing authenticated requests:
85-
/// 1. Obtain token. (Perform authorization as above or get token otherwise.)
86-
/// 2. Use http_client_config::set_oauth2() to set configuration, and construct http_client using it.
87-
/// 3. All requests issued with that http_client will be OAuth 2.0 -authenticated.
92+
/// 1. Perform authorization as above to obtain the access token or use an existing token.
93+
/// - Some services provice option to generate access tokens for testing purposes.
94+
/// 2. Pass the resulting oauth2_config with the access token to http_client_config::set_oauth2().
95+
/// 3. Construct http_client with this http_client_config. After this all requests
96+
/// by that client will be OAuth 2.0 authenticated.
8897
///
8998
/// </summary>
9099
class oauth2_config
@@ -98,6 +107,7 @@ class oauth2_config
98107
m_auth_endpoint(auth_endpoint),
99108
m_token_endpoint(token_endpoint),
100109
m_redirect_uri(redirect_uri),
110+
m_implicit_grant(false),
101111
m_bearer_auth(true),
102112
m_http_basic_auth(true),
103113
m_access_token_key(_XPLATSTR("access_token"))
@@ -106,6 +116,7 @@ class oauth2_config
106116

107117
oauth2_config(utility::string_t token) :
108118
m_token(std::move(token)),
119+
m_implicit_grant(false),
109120
m_bearer_auth(true),
110121
m_http_basic_auth(true),
111122
m_access_token_key(_XPLATSTR("access_token"))
@@ -115,17 +126,25 @@ class oauth2_config
115126
/// <summary>
116127
/// Builds an authorization URI to be loaded in the web browser.
117128
/// The URI is built with auth_endpoint() as basis.
129+
/// The implicit_grant() affects the built URI by selecting
130+
/// either authorization code or implicit grant flow.
118131
/// </summary>
119132
_ASYNCRTIMP utility::string_t build_authorization_uri() const;
120133

121134
/// <summary>
122-
/// Parses authorization code from the redirected URI when resource owner
123-
/// has accepted the authorization.
124-
/// Redirected URI must satisfy the following (otherwise an exception is thrown):
125-
/// - Must contain both 'code' and 'state' query parameters.
126-
/// - The 'state' parameter must be equal to state().
135+
/// Get the access token based on redirected URI.
136+
/// Behavior depends on the implicit_grant() setting.
137+
/// If implicit_grant() is false redirect URI is parsed for 'code' query
138+
/// parameter which is then used to fetch a token
139+
/// from token_endpoint().
140+
/// Otherwise, redirect URI fragment part is parsed for 'access_token'
141+
/// parameter containing the token.
142+
/// In both cases 'state' parameter is parsed and verified to match state().
143+
/// When token is successfully obtained, set_token() is called, and config is
144+
/// ready for use.
145+
/// An oauth2_exception is thrown if anything fails.
127146
/// </summary>
128-
_ASYNCRTIMP utility::string_t parse_code_from_redirected_uri(uri redirected_uri) const;
147+
_ASYNCRTIMP pplx::task<void> token_from_redirected_uri(uri redirected_uri);
129148

130149
/// <summary>
131150
/// Creates a task to fetch token from the token endpoint.
@@ -158,13 +177,21 @@ class oauth2_config
158177
const utility::string_t& state() const { return m_state; }
159178
/// <summary>
160179
/// State string should be unique for each authorization session.
161-
/// This state string should be returned by the authorization server on redirect
180+
/// This state string should be returned by the authorization server on redirect.
162181
/// </summary>
163182
void set_state(utility::string_t state) { m_state = std::move(state); }
164183

165184
const utility::string_t& token() const { return m_token; }
166185
void set_token(utility::string_t token) { m_token = std::move(token); }
167186

187+
bool implicit_grant() const { return m_implicit_grant; }
188+
/// <summary>
189+
/// False means authorization code grant flow is used.
190+
/// True means implicit grant flow is used.
191+
/// Default: False.
192+
/// </summary>
193+
void set_implicit_grant(bool enable) { m_implicit_grant = std::move(enable); }
194+
168195
bool bearer_auth() const { return m_bearer_auth; }
169196
/// <summary>
170197
/// Bearer token passing method. This must be selected based on what the service accepts.
@@ -202,6 +229,7 @@ class oauth2_config
202229
utility::string_t m_scope;
203230
utility::string_t m_state;
204231

232+
bool m_implicit_grant;
205233
bool m_bearer_auth;
206234
bool m_http_basic_auth;
207235
utility::string_t m_access_token_key;

Release/samples/OAuth2Live/MainPage.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<StackPanel Orientation="Horizontal" Margin="0,4,0,4">
2222
<TextBlock TextWrapping="Wrap" Style="{StaticResource BasicTextStyle}" Text="OAuth 2.0 Live sample." VerticalAlignment="Center" Margin="4,0,4,0"/>
2323
<Button x:Name="StartButton" Content="Start" Click="StartButtonClick" Margin="4,0,4,0"/>
24+
<CheckBox x:Name="ImplicitGrantCheckBox" Content="Implicit grant" Unchecked="ImplicitGrantUnchecked" Checked="ImplicitGrantChecked"/>
2425
<Button x:Name="InfoButton" Content="Info" Click="InfoButtonClick" Margin="4,0,4,0" IsEnabled="False"/>
2526
<Button x:Name="ContactsButton" Content="Contacts" Click="ContactsButtonClick" Margin="4,0,4,0" IsEnabled="False"/>
2627
<Button x:Name="EventsButton" Content="Events" Click="EventsButtonClick" Margin="4,0,4,0" IsEnabled="False"/>

Release/samples/OAuth2Live/MainPage.xaml.cpp

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,9 @@ using namespace Windows::UI::Xaml::Media;
2121
using namespace Windows::UI::Xaml::Navigation;
2222
using namespace Windows::Security::Authentication::Web;
2323

24-
//using namespace web;
25-
//using namespace web::http;
26-
//using namespace web::http::client;
27-
//using namespace web::http::client::experimental;
28-
29-
//using namespace web::details;
30-
//using namespace web::http::details;
3124

32-
33-
static const utility::string_t s_live_key = L"0000000048119F29";
34-
static const utility::string_t s_live_secret = L"lJSaBqD42czHGkLIrq4uH9Aadb7LtvIx";
25+
static const utility::string_t s_live_key = L"";
26+
static const utility::string_t s_live_secret = L"";
3527

3628
static const utility::string_t s_state = L"1234ABCD";
3729

@@ -79,42 +71,43 @@ void OAuth2Live::MainPage::StartButtonClick(Platform::Object^ sender, Windows::U
7971
{
8072
String^ statusString;
8173

74+
DebugArea->Text += "< WebAuthenticationBroker returned: ";
8275
switch (result->ResponseStatus)
8376
{
8477
case WebAuthenticationStatus::ErrorHttp:
8578
{
86-
statusString = "ErrorHttp: " + result->ResponseErrorDetail;
79+
DebugArea->Text += "ErrorHttp: " + result->ResponseErrorDetail + "\n";
8780
break;
8881
}
8982
case WebAuthenticationStatus::Success:
9083
{
91-
statusString = "Success";
84+
DebugArea->Text += "Success\n";
9285
utility::string_t data = result->ResponseData->Data();
9386
try
9487
{
95-
statusString += "\nParsing authorization code: ";
96-
utility::string_t code = m_live_oauth2_config.parse_code_from_redirected_uri(data);
97-
AuthorizationCode->Text = ref new String(code.c_str());
98-
statusString += "Success";
88+
DebugArea->Text += "Redirect URI:\n" + result->ResponseData + "\n";
89+
DebugArea->Text += "> Obtaining token from redirect...\n";
90+
m_live_oauth2_config.token_from_redirected_uri(data).then([this]()
91+
{
92+
DebugArea->Text += "< Got token.\n";
93+
AccessToken->Text = ref new String(m_live_oauth2_config.token().c_str());
94+
}, pplx::task_continuation_context::use_current());
9995
}
10096
catch (oauth2_exception& e)
10197
{
10298
String^ error = ref new String(utility::conversions::to_string_t(e.what()).c_str());
103-
statusString += "Error: " + error;
99+
DebugArea->Text += "Error: " + error + "\n";
104100
}
105101
break;
106102
}
107103
default:
108104
case WebAuthenticationStatus::UserCancel:
109105
{
110-
statusString = "UserCancel";
106+
DebugArea->Text += "UserCancel\n";
111107
break;
112108
}
113109
}
114-
115-
DebugArea->Text += "< WebAuthenticationBroker returned: " + statusString + "\n";
116110
});
117-
118111
#endif
119112
}
120113
catch (Exception^ ex)
@@ -123,7 +116,6 @@ void OAuth2Live::MainPage::StartButtonClick(Platform::Object^ sender, Windows::U
123116
}
124117
}
125118

126-
127119
void OAuth2Live::MainPage::InfoButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e)
128120
{
129121
DebugArea->Text += "> Get user info...\n";
@@ -181,7 +173,6 @@ void OAuth2Live::MainPage::AuthCodeTextChanged(Platform::Object^ sender, Windows
181173
}, pplx::task_continuation_context::use_current());
182174
}
183175

184-
185176
void OAuth2Live::MainPage::AccessTokenTextChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::TextChangedEventArgs^ e)
186177
{
187178
http_client_config http_config;
@@ -193,3 +184,13 @@ void OAuth2Live::MainPage::AccessTokenTextChanged(Platform::Object^ sender, Wind
193184
ContactsButton->IsEnabled = true;
194185
EventsButton->IsEnabled = true;
195186
}
187+
188+
void OAuth2Live::MainPage::ImplicitGrantUnchecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
189+
{
190+
m_live_oauth2_config.set_implicit_grant(false);
191+
}
192+
193+
void OAuth2Live::MainPage::ImplicitGrantChecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
194+
{
195+
m_live_oauth2_config.set_implicit_grant(true);
196+
}

Release/samples/OAuth2Live/MainPage.xaml.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ namespace OAuth2Live
2929
void ContactsButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e);
3030
void EventsButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e);
3131

32+
void ImplicitGrantUnchecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
33+
void ImplicitGrantChecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
34+
3235
void AuthCodeTextChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::TextChangedEventArgs^ e);
3336
void AccessTokenTextChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::TextChangedEventArgs^ e);
3437

Release/samples/Oauth2Client/Oauth2Client.cpp

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
2626
INSTRUCTIONS
2727
28-
This sample performs authorization code authorization flow againts
29-
various OAuth 2.0 services and then requests basic user information.
28+
This sample performs authorization code grant flow on various OAuth 2.0
29+
services and then requests basic user information.
3030
3131
This sample is for Windows Desktop, OS X and Linux.
3232
Execute with administrator privileges.
@@ -54,20 +54,19 @@ using namespace web;
5454
using namespace web::http;
5555
using namespace web::http::details;
5656
using namespace web::http::client;
57-
using namespace web::http::experimental::listener;
57+
using namespace web::http::experimental::listener;
5858

5959
// Set to 1 to run an extensive client sample parts.
60-
#define EXTENSIVE 0
60+
#define EXTENSIVE 0
6161

62+
static const utility::string_t s_dropbox_key(U(""));
63+
static const utility::string_t s_dropbox_secret(U(""));
6264

63-
static const utility::string_t s_dropbox_key(U("wvf3odtrwgwq91o"));
64-
static const utility::string_t s_dropbox_secret(U("w4s8zajiz197iip"));
65+
static const utility::string_t s_linkedin_key(U(""));
66+
static const utility::string_t s_linkedin_secret(U(""));
6567

66-
static const utility::string_t s_linkedin_key(U("758evsaj4o491o"));
67-
static const utility::string_t s_linkedin_secret(U("vPRl6ED5jaakbZrx"));
68-
69-
static const utility::string_t s_live_key(U("0000000048119F29"));
70-
static const utility::string_t s_live_secret(U("lJSaBqD42czHGkLIrq4uH9Aadb7LtvIx"));
68+
static const utility::string_t s_live_key(U(""));
69+
static const utility::string_t s_live_secret(U(""));
7170

7271
// State should be generated per authorization/session. Here we just hard-code it.
7372
static const utility::string_t s_state(U("1234ABCD"));
@@ -95,7 +94,7 @@ class oauth2_code_listener
9594
public:
9695
oauth2_code_listener(
9796
uri listen_uri,
98-
const oauth2_config& config) :
97+
oauth2_config& config) :
9998
m_listener(utility::details::make_unique<http_listener>(listen_uri)),
10099
m_config(config)
101100
{
@@ -104,14 +103,15 @@ class oauth2_code_listener
104103
pplx::extensibility::scoped_critical_section_t lck(m_resplock);
105104
try
106105
{
107-
auto code(m_config.parse_code_from_redirected_uri(request.request_uri()));
108-
request.reply(status_codes::OK, U("Ok.")).then([this,code]() -> void
106+
m_config.token_from_redirected_uri(request.request_uri()).then([this,request]() -> void
109107
{
110-
m_tce.set(code);
108+
request.reply(status_codes::OK, U("Ok."));
109+
m_tce.set();
111110
});
112111
}
113-
catch (oauth2_exception&)
112+
catch (oauth2_exception& e)
114113
{
114+
ucout << "Error: " << e.what() << std::endl;
115115
request.reply(status_codes::NotFound, U("Not found."));
116116
}
117117
});
@@ -123,15 +123,15 @@ class oauth2_code_listener
123123
m_listener->close().wait();
124124
}
125125

126-
pplx::task<utility::string_t> listen_for_code()
126+
pplx::task<void> listen_for_code()
127127
{
128128
return pplx::create_task(m_tce);
129129
}
130130

131131
private:
132132
std::unique_ptr<http_listener> m_listener;
133-
pplx::task_completion_event<utility::string_t> m_tce;
134-
const oauth2_config& m_config;
133+
pplx::task_completion_event<void> m_tce;
134+
oauth2_config& m_config;
135135
pplx::extensibility::critical_section_t m_resplock;
136136
};
137137

@@ -188,10 +188,7 @@ class oauth2_session_sample
188188
pplx::task<void> authorization_code_flow()
189189
{
190190
open_browser_auth();
191-
return m_listener->listen_for_code().then([this](utility::string_t auth_code)
192-
{
193-
return m_oauth2_config.fetch_token(auth_code);
194-
});
191+
return m_listener->listen_for_code();
195192
}
196193

197194
http_client_config m_http_config;

0 commit comments

Comments
 (0)