I am in the process of implementing Microsoft SQL Service Reporting Services for my company. SSRS will be called from our company's Java web app. We have decided to use a single sign-on approach when requesting a report from SSRS from the Java web app. With that being the case, we are utilizing forms authentication via a custom security extension to enable single sign-on. As you may already know, after the user submits the UILogon.aspx page, a ticket is created and placed in the cookie called sqlAuthCookie. This cookie (ticket) is then used for authorization whenever the user makes any subsequent requests to SSRS.
The problem I am having is that it appears that the form authentication code, that is written in C# and resides on the SSRS server as a .dll, is not creating a ticket and placing it in the sqlAuthCookie cookie. I've inspected the sqlAuthCookie cookie within the Java web app. by accessing the RSAuthenticationHeader in the response header and the sqlAuthCookie cookie does not contain a value.
So what I want to know is if there is a way that I can put the form authentication code, which is a .dll, in debug within Visual Studio, so that when I log into SSRS from the Java web application, I can step through this code to verify whether or not it is creating the ticket for the cookie.
Please let me know if you require a code snippet.
Code
private void BtnLogon_Click(object sender, System.EventArgs e)
{
bool passwordVerified = false;
try
{
ReportServerProxy server = new ReportServerProxy();
string reportServer = ConfigurationManager.AppSettings["ReportServer"];
string instanceName = ConfigurationManager.AppSettings["ReportServerInstance"];
// Get the server URL from the report server using WMI
server.Url = AuthenticationUtilities.GetReportServerUrl(reportServer, instanceName);
server.LogonUser(TxtUser.Text, TxtPwd.Text, null);
passwordVerified = true;
}
catch (Exception ex)
{
lblMessage.Text = string.Format(CultureInfo.InvariantCulture, ex.Message); ;
return;
}
if (passwordVerified == true)
{
lblMessage.Text = string.Format(CultureInfo.InvariantCulture,
UILogon_aspx.LoginSuccess);
string redirectUrl =
Request.QueryString["ReturnUrl"];
if (redirectUrl != null)
HttpContext.Current.Response.Redirect(redirectUrl, false);
else
HttpContext.Current.Response.Redirect(
"./Folder.aspx", false);
}
else
{
lblMessage.Text = string.Format(CultureInfo.InvariantCulture,
UILogon_aspx.InvalidUsernamePassword);
}
}
}
// Because the UILogon uses the Web service to connect to the report server
// you need to extend the server proxy to support authentication ticket
// (cookie) management
public class ReportServerProxy : ReportingService2005
{
protected override WebRequest GetWebRequest(Uri uri)
{
HttpWebRequest request;
request = (HttpWebRequest)HttpWebRequest.Create(uri);
// Create a cookie jar to hold the request cookie
CookieContainer cookieJar = new CookieContainer();
request.CookieContainer = cookieJar;
Cookie authCookie = AuthCookie;
// if the client already has an auth cookie
// place it in the request's cookie container
if (authCookie != null)
request.CookieContainer.Add(authCookie);
request.Timeout = -1;
request.Headers.Add("Accept-Language",
HttpContext.Current.Request.Headers["Accept-Language"]);
return request;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")]
protected override WebResponse GetWebResponse(WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
string cookieName = response.Headers["RSAuthenticationHeader"];
// If the response contains an auth header, store the cookie
if (cookieName != null)
{
Utilities.CustomAuthCookieName = cookieName;
HttpWebResponse webResponse = (HttpWebResponse)response;
Cookie authCookie = webResponse.Cookies[cookieName];
// If the auth cookie is null, throw an exception
if (authCookie == null)
{
throw new Exception(
"Authorization ticket not received by LogonUser");
}
// otherwise save it for this request
AuthCookie = authCookie;
// and send it to the client
Utilities.RelayCookieToClient(authCookie);
}
return response;
}
private Cookie AuthCookie
{
get
{
if (m_Authcookie == null)
m_Authcookie =
Utilities.TranslateCookie(
HttpContext.Current.Request.Cookies[Utilities.CustomAuthCookieName]);
return m_Authcookie;
}
set
{
m_Authcookie = value;
}
}
private Cookie m_Authcookie = null;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")]
internal sealed class Utilities
{
internal static string CustomAuthCookieName
{
get
{
lock (m_cookieNamelockRoot)
{
return m_cookieName;
}
}
set
{
lock (m_cookieNamelockRoot)
{
m_cookieName = value;
}
}
}
private static string m_cookieName;
private static object m_cookieNamelockRoot = new object();
private static HttpCookie TranslateCookie(Cookie netCookie)
{
if (netCookie == null)
return null;
HttpCookie webCookie = new HttpCookie(netCookie.Name, netCookie.Value);
// Add domain only if it is dotted - IE doesn't send back the cookie
// if we set the domain otherwise
if (netCookie.Domain.IndexOf('.') != -1)
webCookie.Domain = netCookie.Domain;
webCookie.Expires = netCookie.Expires;
webCookie.Path = netCookie.Path;
webCookie.Secure = netCookie.Secure;
return webCookie;
}
internal static Cookie TranslateCookie(HttpCookie webCookie)
{
if (webCookie == null)
return null;
Cookie netCookie = new Cookie(webCookie.Name, webCookie.Value);
if (webCookie.Domain == null)
netCookie.Domain =
HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
netCookie.Expires = webCookie.Expires;
netCookie.Path = webCookie.Path;
netCookie.Secure = webCookie.Secure;
return netCookie;
}
internal static void RelayCookieToClient(Cookie cookie)
{
// add the cookie if not already in there
if (HttpContext.Current.Response.Cookies[cookie.Name] == null)
{
HttpContext.Current.Response.Cookies.Remove(cookie.Name);
}
HttpContext.Current.Response.SetCookie(TranslateCookie(cookie));
}
}
Related
If a cookie is sent with a request from the browser to an asp.net mvc endpoint, it is incomplete (sometimes). The content of the cookie is a small json object, that contains a few information (about 400 chars long).
The cookie is cut after 57 chars.
The cookies are added like this (AddCookieObject):
protected void AddCookieObject(string name, object o, DateTime expires = default(DateTime))
{
AddCookieValue(name, JsonConvert.SerializeObject(o), expires);
}
protected void AddCookieValue(string name, string value, DateTime expires = default(DateTime))
{
var c = new HttpCookie(name, value);
c.Expires = expires;
AddCookie(c);
}
protected void AddCookie(HttpCookie cookie)
{
var cookies = ControllerContext.HttpContext.Response.Cookies;
cookies.Add(cookie);
}
And if I read the cookies using GetCookieObject<T> it is incomplete and json parsing fails:
protected T GetCookieObject<T>(string name)
{
var manager = new LogManager();
string json = GetCookieValue(name);
try
{
if (json != null)
manager.Warning($"Cookie: {name}\r\n{json}");
return json != null ? JsonConvert.DeserializeObject<T>(json) : default(T);
}
catch (Exception)
{
manager.Warning($"Invalid cookie: {name}: {json ?? "<empty>"}");
return default(T);
}
}
protected string GetCookieValue(string name)
{
var cookie = GetCookie(name);
return cookie != null ? cookie.Value : null;
}
protected HttpCookie GetCookie(string name)
{
var cookies = ControllerContext.HttpContext.Request.Cookies;
return cookies.AllKeys.Contains(name) ? cookies[name] : null;
}
Thanks for any help!
I'm creating an app that access the Microsoft Cloud API to get health data. It uses OAuth to log in when you hit the Sign In Button
private void signinButton_Click(object sender, RoutedEventArgs e)
{
UriBuilder uri = new UriBuilder("https://login.live.com/oauth20_authorize.srf");
var query = new StringBuilder();
query.AppendFormat("redirect_uri={0}", Uri.EscapeDataString(RedirectUri));
query.AppendFormat("&client_id={0}", Uri.EscapeDataString(ClientId));
query.AppendFormat("&scope={0}", Uri.EscapeDataString(Scopes));
query.Append("&response_type=code");
uri.Query = query.ToString();
this.webView.Visibility = Visibility.Visible;
this.webView.Navigate(uri.Uri);
}
This brings up a webView with the page to log in using Microsoft credentials. Once completed, it leads to this:
private async void WebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
//
// When the web view navigates to our redirect URI, extract the authorization code from
// the URI and use it to fetch our access token. If no authorization code is present,
// we're completing a sign-out flow.
//
if (args.Uri.LocalPath.StartsWith("/oauth20_desktop.srf", StringComparison.OrdinalIgnoreCase))
{
WwwFormUrlDecoder decoder = new WwwFormUrlDecoder(args.Uri.Query);
var code = decoder.FirstOrDefault((entry) => entry.Name.Equals("code", StringComparison.OrdinalIgnoreCase));
var error = decoder.FirstOrDefault((entry) => entry.Name.Equals("error", StringComparison.OrdinalIgnoreCase));
var errorDesc = decoder.FirstOrDefault((entry) => entry.Name.Equals("error_description", StringComparison.OrdinalIgnoreCase));
// Check the code to see if this is sign-in or sign-out
if (code != null)
{
// Hide the browser again, no matter what happened...
sender.Visibility = Visibility.Collapsed;
if (error != null)
{
this.responseText.Text = string.Format("{0}\r\n{1}", error.Value, errorDesc.Value);
return;
}
var tokenError = await this.GetToken(code.Value, false);
if (string.IsNullOrEmpty(tokenError))
{
this.responseText.Text = "Successful sign-in!";
this.signoutButton.IsEnabled = true;
this.signinButton.IsEnabled = false;
this.getProfileButton.IsEnabled = true;
this.getDevicesButton.IsEnabled = true;
this.getActivitiesButton.IsEnabled = true;
this.getDailySummaryButton.IsEnabled = true;
this.getHourlySummaryButton.IsEnabled = true;
}
else
{
this.responseText.Text = tokenError;
}
}
else
{
this.responseText.Text = "Successful sign-out!";
this.signoutButton.IsEnabled = false;
this.signinButton.IsEnabled = true;
this.getProfileButton.IsEnabled = false;
this.getDevicesButton.IsEnabled = false;
this.getActivitiesButton.IsEnabled = false;
this.getDailySummaryButton.IsEnabled = true;
this.getHourlySummaryButton.IsEnabled = false;
}
}
}
private async Task<string> GetToken(string code, bool isRefresh)
{
UriBuilder uri = new UriBuilder("https://login.live.com/oauth20_token.srf");
var query = new StringBuilder();
query.AppendFormat("redirect_uri={0}", Uri.EscapeDataString(RedirectUri));
query.AppendFormat("&client_id={0}", Uri.EscapeDataString(ClientId));
query.AppendFormat("&client_secret={0}", Uri.EscapeDataString(ClientSecret));
if (isRefresh)
{
query.AppendFormat("&refresh_token={0}", Uri.EscapeDataString(code));
query.Append("&grant_type=refresh_token");
}
else
{
query.AppendFormat("&code={0}", Uri.EscapeDataString(code));
query.Append("&grant_type=authorization_code");
}
uri.Query = query.ToString();
var request = WebRequest.Create(uri.Uri);
try
{
using (var response = await request.GetResponseAsync())
{
using (var stream = response.GetResponseStream())
{
using (var streamReader = new StreamReader(stream))
{
var responseString = streamReader.ReadToEnd();
var jsonResponse = JObject.Parse(responseString);
this.creds.AccessToken = (string)jsonResponse["access_token"];
this.creds.ExpiresIn = (long)jsonResponse["expires_in"];
this.creds.RefreshToken = (string)jsonResponse["refresh_token"];
string error = (string)jsonResponse["error"];
return error;
}
}
}
}
catch (Exception ex)
{
return ex.Message;
}
}
I don't want users to have to accept the permissions every time the app is launched. Is there a way to save credentials locally so that it automatically authenticates on launch? Thanks!
You can use
Windows.Storage.ApplicationData.Current.LocalSettings
This process good described by this answer Best Way to keep Settings for a WinRT App?
The code in link identity to UWP
Store the needed oauth parts in the credential locker API. Never store these kind of information in the normal settings API.
On start read the oauth information and use the refreshtoken to get a new access token.
More Information here.
https://msdn.microsoft.com/en-us/library/windows/apps/mt270189.aspx
I am trying to authenticate my SharePoint service t retrieve SPList Items :
private Cookie AuthenticateFBASite(string AuthenticationSiteURL, string UserName, string Password, NetworkCredential nc2)
{
Cookie CurrentSiteCookie = null;
using (Authentication.Authentication authSvc = new Authentication.Authentication())
{
authSvc.Url = AuthenticationSiteURL + "/_vti_bin/authentication.asmx";
authSvc.CookieContainer = new System.Net.CookieContainer(); //create a new cookie container
//set the FBA login information
authSvc.AllowAutoRedirect = true;
authSvc.PreAuthenticate = true;
authSvc.Credentials = nc2;
Authentication.LoginResult result = authSvc.Login(UserName, Password);
if (result.ErrorCode == Authentication.LoginErrorCode.NoError)
{
try
{
CookieCollection cookies = authSvc.CookieContainer.GetCookies(new Uri(AuthenticationSiteURL));
CurrentSiteCookie = cookies[result.CookieName];
return CurrentSiteCookie;
}
catch (System.Exception ex)
{
//Console.WriteLine("Exception occured while calling lists.asmx" + ex.Message);
return CurrentSiteCookie;
}
}
else if (result.ErrorCode == Authentication.LoginErrorCode.PasswordNotMatch)
{
return CurrentSiteCookie;
}
else
return CurrentSiteCookie;
}
}
and it was working fine till today i try to use it again but it return me an eror cookies[result.CookieName] is null , and this only happens on my machine not other machine .
#Eslan May i knw fom where your are calling this code ? from webpart or app or console application ? I suspect its authentication mode issue.
I have a generic handler written in C# - this is called as part of an OAuth2 process to validate users via Google.
Once the correct user is identified I need to set a cookie so the rest of the site can then identify the user.
The trouble is in order to set session variables the handler needs to implement IRequiresSessionState - when I do that - then the OAuth 2 process fails with the following error.
Unexpected OAuth authorization response received with callback and client state that does not match an expected value
So I can implement OAuth or write a session variable but cannot do both. I could get OAuth to call the first page but then the code can be seen in the URL (which I would rather not do - as it gives clues for any nefarious person to break security ). I could get a page to call the handler, return JSON to identify the user and have the page itself set the session variable, then go to the first page - but this page would have no content, as well as requiring two hops - so how can you have an HTML page which is essentially empty, or set the session without IRequiresSessionState breaking the session.
The code for the OAuth handler is shown below.
public void ProcessRequest(HttpContext context)
{
NetworkParameters networkParameters = null;
NetworkParameter networkParameter = null;
WebServerClient consumer = null;
AuthorizationServerDescription server = null;
IAuthorizationState grantedAccess = null;
LoginResult loginResult = null;
String code = String.Empty;
String result = String.Empty;
String consumerSecret = String.Empty;
String consumerKey = String.Empty;
String securityCookieVal = String.Empty;
Uri tokenEndpoint = null;
Uri authorizationEndpoint = null;
Profile profile = null;
Profile profile2 = null;
Profiles profiles = null;
NetworkAuthorizations authorizations = null;
NetworkAuthorization na = null;
try
{
loginResult = new LoginResult();
tokenEndpoint = new Uri("https://accounts.google.com/o/oauth2/token");
authorizationEndpoint = new Uri("https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=auto");
// retrieve network parameters
networkParameters = new NetworkParameters(Properties.Settings.Default.DatabaseConnection);
authorizations = new NetworkAuthorizations(Properties.Settings.Default.DatabaseConnection);
networkParameter = networkParameters.Select("GOOGLE");
code = context.Request["code"];
consumerKey = networkParameter.ClientId;
consumerSecret = networkParameter.ClientSecret;
// set up request
server = new AuthorizationServerDescription();
server.AuthorizationEndpoint = authorizationEndpoint;
server.TokenEndpoint = tokenEndpoint;
server.ProtocolVersion = ProtocolVersion.V20;
// initialise webserver client
consumer = new WebServerClient(server, consumerKey, consumerSecret);
consumer.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(consumerSecret);
// retrieve access
grantedAccess = consumer.ProcessUserAuthorization();
profile = GoogleServices.GetProfile(grantedAccess.AccessToken);
profiles = new Profiles(Properties.Settings.Default.DatabaseConnection);
profile2 = profiles.SelectByNetworkId(profile.Network, profile.NetworkId);
if (profile2 == null)
{
na = new NetworkAuthorization()
{
Id = Guid.NewGuid().ToString(),
AccessToken = grantedAccess.AccessToken,
ExpirationDate = (DateTime)grantedAccess.AccessTokenExpirationUtc,
IssueDate = (DateTime)grantedAccess.AccessTokenIssueDateUtc,
RefreshToken = grantedAccess.RefreshToken,
Network = profile.Network,
NetworkId = profile.NetworkId
};
authorizations.Insert(na);
profiles.Insert(profile);
}
loginResult.UserId = profile.NetworkId;
}
catch (System.Exception e)
{
loginResult.Status.Status = "ERROR";
loginResult.Status.Message = e.Message;
}
finally
{
context.Response.ContentType = "application/json";
context.Response.Write(JsonConvert.SerializeObject(loginResult));
}
}
Not really an answer - but I got around this by passing a randomly generated id to the first page of the website, and storing it against the user - cookie was set when the first page was called.
Not really secure sending such information in the query string but will suffice in what is a prototype - eventual plan is to use Node.js where this will not be an issue.
I am writing C# client for Instagram. I've registered my application and filled the fields: Application Name, Description, Website, OAuth redirect_uri. But I receive this error message in my C# client:
This client is not xAuth enabled.
I think the problem is in Website, OAuth redirect_uri fields. What values must I put in these fields?
Here is method that have to get access_token (HttpRequest class from xNet library):
private string GetAccessToken()
{
using (var request = new HttpRequest())
{
var urlParams = new RequestParams();
urlParams["client_id"] = "ce3c76b914cb4417b3721406d7fe3456";
urlParams["client_secret"] = "b8ad0c21ce8142d0a8c0fa2d2bd78f53";
urlParams["username"] = this.login;
urlParams["password"] = this.password;
urlParams["grant_type"] = "password";
urlParams["scope"] = "comments likes relationships";
try
{
this.json = request.Post("https://api.instagram.com/oauth/access_token", urlParams).ToString();
var values = JsonConvert.DeserializeObject<InstagramResponse>(this.json);
return values.access_token;
}
catch (Exception)
{
return null;
}
}
}