Report Server authentication in .net core 2.1 linux container - docker

I am migrating a .net core 2.1 app from windows server to linux container. It uses SQL Server 2008 report server.
The old app version is running on IIS (windows server), application pool with identity configured (active directory user).
The new app version is running on an alpine container using kestrel .net core server standalone, no identity configured.
When the app tries to reach SQL Server 2008 report server there is an error:
LoadReport error: One or more errors occured. (NTLM authentication is not possible with default credentials on this platform.)
How can I configure credentials (username and password)(same one set in my old application pool) in my new app based on linux container?
Part of my appsettings.json:
"Reporting": {
"ServerUrl": "http://myserver/ReportServer",
"ReportPath": "/Folder/Reports/"
},
Part of the source code:
private ServerReport PrepararRelatorio()
{
ReportSettings settings = new ReportSettings
{
ReportServer = this.configuration["Reporting:ServerUrl"]
};
ServerReport serverReport = new ServerReport(settings);
return serverReport;
}
protected FileContentResult CarregarRelatorio(
string nomeRelatorio,
string extensao,
Dictionary<string,string> parametros)
{
var renderType = this.ObterTipoRenderizacao(extensao);
if (ReportRenderType.Null.Equals(renderType))
{
throw new BusinessException("Erro ao definir o tipo do arquivo a ser exportado.");
}
ServerReport serverReport = this.PrepararRelatorio();
ReportRequest request = new ReportRequest
{
RenderType = renderType,
Path = this.configuration["Reporting:ReportPath"] + nomeRelatorio,
Name = nomeRelatorio,
ExecuteType = ReportExecuteType.Export,
Parameters = parametros
};
ReportResponse response = serverReport.Execute(request);
if (response.Status != 0)
{
throw new BusinessException(response.Message);
}
return File(response.Data.Stream, response.Data.MimeType, nomeRelatorio + "." + extensao);
}

Microsoft don't provide support for .NET Core/.NET 5, since the SSRS
library is intricately linked with WebForms, which are no longer
supported.
Refer this link
Usually, we use NetworkCredential option to pass username and password while in ASP.NET MVC.
You can able to supply report server's username and password to ReportSettings.Credential as shown in below.
Configuration:
"Reporting": {
"ServerUrl": "http://myserver/ReportServer",
"ReportPath": "/Folder/Reports/",
"UserName": "xxxxxx",
"Password": "yyyyyy"
},
Source Code:
private ServerReport PrepararRelatorio()
{
ReportSettings settings = new ReportSettings
{
ReportServer = this.configuration["Reporting:ServerUrl"],
Credential = NetworkCredential(this.configuration["Reporting:UserName"], this.configuration["Reporting:Password"])
};
ServerReport serverReport = new ServerReport(settings);
return serverReport;
}

Related

NewPageAsync(): WebSocketException: The WebSocket is in an invalid state ('Aborted') for this operation. Valid states are: 'Open, CloseReceived'

I'm trying to write a simple HTML to PDF converter with puppeteer-sharp. It is going to be part of MVC.NET project.
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true,
ExecutablePath = #"C:\Dev\NewPdfLib\chrome-win\chrome.exe",
Args = new string[] { "--disable-gpu" },
Timeout = 0,
UserDataDir = workingFolder
})
var page = await browser.NewPageAsync();
//await page.GoToAsync("http://www.google.com");
//await page.PdfAsync(output);
When I run this code an exception "WebSocketException: The WebSocket is in an invalid state ('Aborted') for this operation. Valid states are: 'Open, CloseReceived'" is thrown at browser.NewPageAsync() line.
The system is Windows 10 and the project is in .NET Framework 4.8

clear cached TFS client credentials

Please help me to clear TFS cached credentials using c# code. I'm using TFS API to access source code hosted by the Dev ops TFS server at https://dev.azure.com
sometimes (after domain password is changed) it raises 401 error when access the source code server. Please find code sample used to connect below:
var u = "https://dev.azure.com/orgid";
var vssCred = new VssClientCredentials();
if (cacheCred)
vssCred.Storage = new VssClientCredentialStorage(); // tried with storage and without
Logger.Debug("getting vsts collection for url:{0}", u);
TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(u, vssCred);
try
{
Logger.Debug("authenticating");
tpc.Authenticate();
tpc.GetService<VersionControlServer>();
it uses Microsoft.TeamFoundationServer.ExtendedClient.15.131.1 and Microsoft.TeamFoundationServer.Client.15.131.1 packages.
I've tried to clear cached credentials using the code like below:
IEnumerable<string> ClearCachedTokens(VssCredentials cred, Uri address)
{
if (cred == null) return null;
var res = new Collection<string>();
foreach (VssCredentialsType enumValue in Enum.GetValues(typeof(VssCredentialsType)))
try
{
var token = cred.Storage.RetrieveToken(address, enumValue);
if (token != null)
{
var tokenData = string.Join(";", token.Properties.Select(_ => string.Format("{0}={1}", _.Key, _.Value)));
Logger.Debug("got token {0} {1}", enumValue, tokenData);
cred.Storage.RemoveToken(address, token);
res.Add(address.ToString());
}
}
catch (Exception ec)
{
Logger.Warn("can't clear token type:{0} error:{1}", enumValue, ec.Message);
}
return res;
}
but it does not return any entry and the error still persist.
However error is gone when I delete %appdata%Local\Microsoft\Team Foundation\7.0\Cache content and run tf.exe get command. It asks me for login and password and then 401 error is not shown any more when tpc.Authenticate(); is executed.
How can I clear cached credentials in the Cache folder using the TeamFoundationServer.Client or TeamFoundationServer.ExtendedClient API?
The credential might have been saved in the Credential Manager store (Control Panel\All Control Panel Items\Credential Manager) in the Generic Credentials group.

How to save the file to a specific folder (Network Drive or local folder) on a client machine?

I have an asp.net web app which is published as an Azure cloud service.The application downloads the files from the server and saves it locally on the client machine.However,It does not seem to work when published as a cloud service.It works fine when published locally using IIS.
The code below is the where the file gets saved.
foreach (var item in userids)
{
//item.contractorpath= user filepath(client machine path eg, C:\test\)
string filePath =
Path.Combine(Server.MapPath("~/Content/Downloads"),
SessionInfo.CompanyId.ToString(), "Bill",
item.ContractorId.ToString());
if (Directory.Exists(filePath))
{
//System.IO.Directory.CreateDirectory(filePath);
DirectoryInfo di = new DirectoryInfo(filePath);
FileInfo[] TXTFiles = di.GetFiles("*.pdf");
if (TXTFiles.Length > 0)
{
foreach (FileInfo file in TXTFiles)
{
string fileName = file.Name;
if (!Directory.Exists(item.FolderPath))
{
System.IO.Directory.CreateDirectory(item.FolderPath);
}
using (WebClient webClient = new WebClient())
{
webClient.DownloadFile(Path.Combine(filePath, file.Name), Path.Combine(item.FolderPath, file.Name));
System.IO.File.Delete(Path.Combine(filePath, file.Name));
}
}
}
}
}

Project Server In premise 2016 CSOM code with Claim based Authentication

One of our clients has enabled ADFS on his Project server 2016 In premise environment . We are using CSOM operation in our custom application and CSOM operations have failed due to this change.
For ADFS Claims based authentication we need to pass Authenticated cookie . Can someone help us with how to add authenticated Cookie with CSOM code.
Existing CSOM Code for getting list of projects:
public static void GetProjectListInpremise()
{
NetworkCredential net = null;
Console.WriteLine("Read Project Online Started ..");
string PWAOnlineUrl = ConfigurationManager.AppSettings ["pwaInpremiseUrl"];
string userName = ConfigurationManager.AppSettings["pwaInpremiseUser"];
string password = ConfigurationManager.AppSettings["pwaInpremiseUserPwd"];
string domain = ConfigurationManager.AppSettings["pwaInpremiseDomian"];
net = new NetworkCredential(userName, password, domain);
ProjectContext projContext = null;
projContext = new ProjectContext(PWAOnlineUrl);
// projContext.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication;
projContext.Credentials = net;
projContext.Load(projContext.Projects);
projContext.ExecuteQuery();
Console.WriteLine("Read Project Execute Query Successful..");
foreach (PublishedProject pubProj in projContext.Projects)
{
Console.WriteLine("Project Name :" + pubProj.Name);
}
Console.ReadLine();
}

ADFS 2.0 Windows 2008 R2 Web API

I would like to make a MVC Web Application that talks to a Web API application and use ADFS 2.0 (on Windows 2008 R2) for authentication.
I managed to make the MVC Web Application to authenticate using ADFS.
Q: But I don't know how I should federate my ADFS 2.0 (on Windows 2008 R2) from MVC Web to Web API (assuming they will be deployed in separate servers)?
I found a lot of articles on how to do this with WCF or Windows Server 2012 R2, but not with Web API and ADFS 2.0 in Windows Server 2008 R2
Edit, In the end I went for poor man delegation(passing the same token that I receive to the front end to the backend (as it would not make sense to call the adfs again)
FrontEnd -> Call GetToken and put in on the authorization header (I encode it to base64)
public string GetToken()
{
BootstrapContext bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
string token = bootstrapContext.Token;
if (string.IsNullOrEmpty(token))
token = ToTokenXmlString(bootstrapContext.SecurityToken as SamlSecurityToken);
return token;
}
string ToTokenXmlString(SecurityToken token)
{
var genericToken = token as GenericXmlSecurityToken;
if (genericToken != null)
return genericToken.TokenXml.OuterXml;
var handler = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
return ToTokenXmlString(token, handler);
}
string ToTokenXmlString(SecurityToken token, SecurityTokenHandlerCollection handler)
{
if (!handler.CanWriteToken(token))
throw new InvalidOperationException("Token type not suppoted");
var sb = new StringBuilder(128);
using (StringWriter stringWriter = new StringWriter(sb))
{
using (var textWriter = new XmlTextWriter(stringWriter))
{
handler.WriteToken(textWriter, token);
return sb.ToString();
}
}
}
Backend-> Parse and validate the token->
public ClaimsIdentity GetIdentityFromToken(string tokenBase64)
{
if (string.IsNullOrEmpty(tokenBase64))
return null;
byte[] tokenByteArray = Convert.FromBase64String(tokenBase64);
string decodedToken = Encoding.UTF8.GetString(tokenByteArray);
if (string.IsNullOrWhiteSpace(decodedToken))
return null;
try
{
var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;
SecurityToken token;
using (StringReader stringReader = new StringReader(decodedToken))
{
using (XmlTextReader xmlReader = new XmlTextReader(stringReader))
{
token = handlers.ReadToken(xmlReader);
}
}
if (token == null)
return null;
return handlers.ValidateToken(token).FirstOrDefault();
}
catch (Exception e)
{
logger.Error(new AuthenticationException("Error validating the token from ADFS", e));
return null;
}
}
I implemented this by passing the bearer token that I received from Adfs into the authorization header of the web api call, and then using the Microsoft.Owin.Security.Jwt nuget package to translate the token into the httpcontext current identity during owin startup in the web api project.
This example uses a jwt token as the bearer token. Choose the proper NuGet package for the token type that you want to use.
Construct the WebRequest in mvc controller
BootstrapContext bc = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
HttpWebRequest request = WebRequest.Create(ConfigurationManager.AppSettings["ApiUrl"]) as HttpWebRequest;
request.Method = "GET";
request.Headers["Authorization"] = "Bearer " + bc.Token;
Owin Startup.cs file in web api Before the app.UseWebApi(config) line.
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { ConfigurationSettings.AppSettings["ida:Realm"] },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(
ConfigurationSettings.AppSettings["ida:ValidIssuer"],
ConfigurationSettings.AppSettings["ida:SymmetricKey"])
},
Provider = new OAuthBearerAuthenticationProvider
{
OnValidateIdentity = context =>
{
return System.Threading.Tasks.Task.FromResult<object>(null);
}
}
});

Resources