I need to develop a SoapUi test using to oauth2, the authorization API requires Basic Authentication.
I tried to use the [username]:[password]#url approch, but the password contains a special character # that gets changed to %40, I also changed the Enconding but no luck.
I added the header in the class EnabledWebViewBasedBrowserComponent
public void navigate(final String url, String errorPage) {
if (SoapUI.isBrowserDisabled()) {
return;
}
setErrorPage(errorPage);
this.url = url;
Platform.runLater(new Runnable() {
public void run() {
getWebEngine().setUserAgent("\nAuthorization: Basic bWNb25lhbGRzlk1jRDuGxklWg==");
getWebEngine().load(url);
}
});
}
Related
using TFS in our internal network, want to programatically check in changes with an access token, but get this: InvalidOperationException Basic authentication requires a secure connection to the server. Is there a way to turn off requiring secure connection?
var basicCreds = new VssBasicCredential(string.Empty, BuildUnitTestConstants.AccessToken);
var connection = new VssConnection(new Uri(BuildUnitTestConstants.ProjectUri), basicCreds);
var sourceControlServer = connection.GetClient<TfvcHttpClient>();
Well, it is possible, albeit not recommended; I needed it as well, because internal IT department would not install TFS with HTTPS (sad story). Also, for testing scenarios it can come quite handy.
As always YMMV and I'm not responsible for what happens when you use it when you shouldn't ;-) You have been warned.
For one you could simply not use the .NET client API, but directly use HttpClient and manually put the PAT in the URL to access the REST API, e.g.:
http://<WHATEVER>:<BASE64PAT>#<instance>/_apis/...
(Hence that the tfx-cli works nicely with PATs and non-HTTPS TFS instances, most likely because it does just that internally, not using the .NET client API of course - it is a node.js thing.)
If you want to stay with the .NET client API, you can create your own credentials class like so:
using System;
using System.Linq;
using System.Net;
using Microsoft.VisualStudio.Services.Common;
namespace Utilities
{
/// <summary>
/// Same as VssBasicCredential, but doesn't throw when URL is a non SSL, i.e. http, URL.
/// </summary>
/// <inheritdoc cref="FederatedCredential"/>
internal sealed class PatCredentials : FederatedCredential
{
public PatCredentials()
: this((VssBasicToken)null)
{
}
public PatCredentials(string userName, string password)
: this(new VssBasicToken(new NetworkCredential(userName, password)))
{
}
public PatCredentials(ICredentials initialToken)
: this(new VssBasicToken(initialToken))
{
}
public PatCredentials(VssBasicToken initialToken)
: base(initialToken)
{
}
public override VssCredentialsType CredentialType => VssCredentialsType.Basic;
public override bool IsAuthenticationChallenge(IHttpResponse webResponse)
{
if (webResponse == null ||
webResponse.StatusCode != HttpStatusCode.Found &&
webResponse.StatusCode != HttpStatusCode.Found &&
webResponse.StatusCode != HttpStatusCode.Unauthorized)
{
return false;
}
return webResponse.Headers.GetValues("WWW-Authenticate").Any(x => x.StartsWith("Basic", StringComparison.OrdinalIgnoreCase));
}
protected override IssuedTokenProvider OnCreateTokenProvider(Uri serverUrl, IHttpResponse response)
{
return new BasicAuthTokenProvider(this, serverUrl);
}
private sealed class BasicAuthTokenProvider : IssuedTokenProvider
{
public BasicAuthTokenProvider(IssuedTokenCredential credential, Uri serverUrl)
: base(credential, serverUrl, serverUrl)
{
}
protected override string AuthenticationScheme => "Basic";
public override bool GetTokenIsInteractive => this.CurrentToken == null;
}
}
}
Then create your VssCredentials using this class:
var credentials = new PatCredentials("", personalAccessToken);
var connection = new VssConnection(serverUrl, credentials);
(Shameless plug I use it in my TfsInfoService).
Nowadays you don't need to use the workaround provided by #Christian.K
Simply set the following env variable:
VSS_ALLOW_UNSAFE_BASICAUTH=true
Source: code of Microsoft.VisualStudio.Services.Common.VssBasicCredential:
protected override IssuedTokenProvider OnCreateTokenProvider(
Uri serverUrl,
IHttpResponse response)
{
bool result;
if (serverUrl.Scheme != "https" && (!bool.TryParse(Environment.GetEnvironmentVariable("VSS_ALLOW_UNSAFE_BASICAUTH") ?? "false", out result) || !result))
throw new InvalidOperationException(CommonResources.BasicAuthenticationRequiresSsl());
return (IssuedTokenProvider) new BasicAuthTokenProvider(this, serverUrl);
}
To set the environment variable programatically:
Environment.SetEnvironmentVariable("VSS_ALLOW_UNSAFE_BASICAUTH", "true")
No this is not possible. The problem of enabling PAT over unsecured connections is that anyone could intercept the token easily and would be able to use it for their own purposes.
Either enable SSL on the TSF instance, this is highly recommended. Or use Windows Authentication to use a secure form of authentication to TFS over an unsecured channel.
I am using a 3rd party library names telogis map in my project. For one of its functionality called Clustering, it is not possible to send request header. Only query string can be passed for clustering and entire logic of API call is done within the JS library.
My project use Bearer token based authenticate and built with Web API 2. To resolve this issue I have passed access token in query string and want validate the request. I created below CustomAuthorize attribute for this:
public class ClusterRequestAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
}
public override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
string accessToken = actionContext.Request.GetQueryNameValuePairs().Where(w => w.Key == "access_token").Select(w => w.Value).DefaultIfEmpty().FirstOrDefault();
actionContext.Request.Headers.Remove("Authorization");
actionContext.Request.Headers.Add("Authorization", accessToken);
actionContext.ControllerContext.Request.Headers.Remove("Authorization");
actionContext.ControllerContext.Request.Headers.Add("Authorization", accessToken);
HttpContext.Current.Request.Headers.Remove("Authorization");
HttpContext.Current.Request.Headers.Add("Authorization", accessToken);
return base.OnAuthorizationAsync(actionContext, cancellationToken);
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
return base.IsAuthorized(actionContext);
}
}
But IsAuthorized is always returning false. I reviewed the Authorize API internal function using Git Link
According to it, I have to set actionContext.ControllerContext.RequestContext.Header which is not accessible due to protection level as it is marked as internal.
Is there any other work around for this issue or can it be done in better way?
I am using Spring security in my application and configuration is mentioned below.
When User is logged out from system and click in again login then I want to display login page.
#Component
#EnableOAuth2Sso
public static class LoginConfigurer extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
RequestMatcher csrfRequestMatcher = new RequestMatcher() {
// Enabled CSFR protection on the following urls
private AntPathRequestMatcher[] requestMatchers = { new AntPathRequestMatcher("/dashboard/logout") };
#Override
public boolean matches(HttpServletRequest request) {
// If the request match one url the CSFR protection will be
// enabled
for (AntPathRequestMatcher rm : requestMatchers) {
if (rm.matches(request)) {
return true;
}
}
return false;
} // method matches
};
http.csrf().requireCsrfProtectionMatcher(csrfRequestMatcher).csrfTokenRepository(csrfTokenRepository())
.and().antMatcher("/dashboard/**").authorizeRequests().anyRequest()
.hasAnyRole("AUTHENTICATED_USER", "ANONYMOUS").and().sessionManagement().sessionFixation()
.migrateSession().and()
// .csrfTokenRepository(csrfTokenRepository()).and()
// .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.logout().invalidateHttpSession(true).logoutUrl("/dashboard/logout").deleteCookies(new String[]{"XSRF-TOKEN","JSESSIONID","remember-me"})
.logoutSuccessUrl("/").permitAll().and().rememberMe().and()
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
}
The case you mentioned mostly happens if you use a cookie for authentication as a token and the deleteCookie method is not deleting your authentication cookies correctly.
The best way to identify this is follow :
1.Clear all cookies and login and then observe the cookie name and value and path in inspect element of web browser.
2.Logout and then observe the inspect element request and response with cookies.
3.Observe the path of the cookie carefully.
It is important to observe the path of the cookie is because of the path of the cookie at its creation time is different than its deletion time,it will not get deleted.It has to be exactly the same.
When you call .deleteCookies(...),then internally it calls the CookieClearingLogoutHandler(spring boot security internal class) mentioned as below :
public final class CookieClearingLogoutHandler implements LogoutHandler {
private final List<String> cookiesToClear;
public CookieClearingLogoutHandler(String... cookiesToClear) {
Assert.notNull(cookiesToClear, "List of cookies cannot be null");
this.cookiesToClear = Arrays.asList(cookiesToClear);
}
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
for (String cookieName : cookiesToClear) {
Cookie cookie = new Cookie(cookieName, null);
String cookiePath = request.getContextPath();
if(!StringUtils.hasLength(cookiePath)) {
cookiePath = "/";
}
cookie.setPath(cookiePath);
cookie.setMaxAge(0);
response.addCookie(cookie);
}
}
}
Observe the cookie setPath, you would need to set the cookie path for the cookie you are using for authentication in the same way mentioned in above code.
Hope this helps.
I create a custom BasicAuthenticationMiddleware that use a BasicAuthenticationHandler to Authenticate requests from client to WebAPI.
The BasicAuthenticationHandler derives from the AuthenticationHandler< TOptions > base class.
Everything works fine and I implemented the
AuthenticateCoreAsync
where the logic to authenticate happens
ApplyChallengeResponseAsync
where the logic, in case of not authenticated requests, sends the WWW-Authenticate header to the client.
What I would like to achieve now is to set a Custom Body in the Response (IOwinResponse, inside the ApplyChallengeResponseAsync, with a custom object like:
{
Code="999",
Description="My failing reason"
AdditionalInfo = "My additional infos"
}
instead of the standard message that is like
{
message="Authorization has been denied for this request."
}
Did you have any suggestion on this?
thanks
The standard message you see, which is "Authorization has been denied for this request." is created by the Authorize filter. The HandleUnauthorizedRequest method sets this message in the response.
protected virtual void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw Error.ArgumentNull("actionContext");
}
actionContext.Response = actionContext.ControllerContext.Request
.CreateErrorResponse(
HttpStatusCode.Unauthorized,
SRResources.RequestNotAuthorized);
}
SRResources.RequestNotAuthorized is what you see as the standard message.
Now, ApplyChallengeResponseAsync is called from the OnSendingHeaders callback in Katana autentication micro framework. This callback is invoked when a component writes into the response stream. In our case, when the response message created by the filter (what you see above) gets serialized, that is when the callback is invoked and ApplyChallengeResponseAsync runs. By that time, it is already too late for you to change the response. The best bet will be to override the virtual method of the Authorize filter above like this.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
var response = actionContext.Request.CreateResponse<MyError>
(new MyError() { Description = "My failing reason" });
response.StatusCode = HttpStatusCode.Unauthorized;
actionContext.Response = response;
}
}
public class MyError
{
public string Description { get; set; }
}
Instead of using [Authorize] on the controller or action method, use [MyAuthorize].
Is it possible to make my application ask for username and password prompting for it before render a view?
Just like on twitter API to get information about your account:
http://twitter.com/account/verify_credentials.xml
So before render the view || file it asks you to insert you username and password, I think this is made directly on the server since the curl request is based on username:password as well like this:
curl -u user:password http://twitter.com/account/verify_credentials.xml
As I'm trying to build an API following the same structure I would like to know how I can do this on ASP.NET MVC C#. I've already used this on ruby rails and its pretty simple like:
before_filter :authenticate
def authenticate
authenticate_or_request_with_http_basic do |username, password|
username == "foo" && password == "bar"
end
I don't think that [Authorize] filter is the same since I believe it's just a redirection,
and it redirects you to the Accounts Internal Controller that is based on the accounts database, in this case I will use another database, specifically from a webservice and do the validation after the information is submitted.
But I need the action to require the user and pass credentials on its request.
Thanks in advance
UPDATE:
Actually to request a page that requires this authentication (i.e. Twitter)
I would have to declare this on its request
request.Credentials = new NetworkCredential("username", "password");
And this would reflect that prompted username and password.
So, it's exactly the same thing but from the other side, if it's possible to provide information to the authentication prompt on request, how could I require this authentication on the request instead?
So everytime somebody tries to make a request to my application on example:
http://myapplication/clients/verify_credentials
it should ask for a username and password with that server prompt
so to retrive information on curl for example it would be like this
curl -u user:password http://myapplication/clients/verify_credentials
Well, to require basic authentication you need to return 401 status code. But doing that will cause the current authentication module to execute its default unauthorized handler (for forms authentication, this means redirecting to login page).
I wrote an ActionFilterAttribte to see if I can get the behaviour you want when there's no authentication module installed in web.config.
public class RequireBasicAuthentication : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
var req = filterContext.HttpContext.Request;
if (String.IsNullOrEmpty(req.Headers["Authorization"])) {
var res = filterContext.HttpContext.Response;
res.StatusCode = 401;
res.AddHeader("WWW-Authenticate", "Basic realm=\"Twitter\"");
res.End();
}
}
}
And the controller action :
[RequireBasicAuthentication]
public ActionResult Index() {
var cred = System.Text.ASCIIEncoding.ASCII
.GetString(Convert.FromBase64String(
Request.Headers["Authorization"].Substring(6)))
.Split(':');
var user = new { Name = cred[0], Pass = cred[1] };
return Content(String.Format("user:{0}, password:{1}",
user.Name, user.Pass));
}
That action successfully prints the username and password I enter. But I really doubt that's the best way to do this. Do you have no choice except asking for username and password this way?
You really want to create a service and not a web application, based on what I have read. I am guessing here, but I think you picked ASP.NET MVC to take advantage of the routing and building the URL's the way you want? Correct me if I am wrong.
In my opinion the best way to solve the problem you are having is to build RESTful web services with WCF if you are returning data. This article should help you get started if you want to go this route.
Otherwise, you will need to go further up the stack for handling the request and authenticating it. If this is the case, I can help with providing more info and code.
I modified the çağdaş answer to put the whole logic inside my custom ActionFilter attribute.
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
public string BasicRealm { get; set; }
protected string Username { get; set; }
protected string Password { get; set; }
public BasicAuthenticationAttribute(string username, string password)
{
this.Username = username;
this.Password = password;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var req = filterContext.HttpContext.Request;
var auth = req.Headers["Authorization"];
if (!String.IsNullOrEmpty(auth))
{
var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
var user = new { Name = cred[0], Pass = cred[1] };
if (user.Name == Username && user.Pass == Password) return;
}
var res = filterContext.HttpContext.Response;
res.StatusCode = 401;
res.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Ryadel"));
res.End();
}
}
It can be used to put under Basic Authentication a whole controller:
[BasicAuthenticationAttribute("your-username", "your-password",
BasicRealm = "your-realm")]
public class HomeController : BaseController
{
...
}
or a specific ActionResult:
public class HomeController : BaseController
{
[BasicAuthenticationAttribute("your-username", "your-password",
BasicRealm = "your-realm")]
public ActionResult Index()
{
...
}
}
NOTE: The above implementation requires the developer to manually insert the username and password as ActionFilter required parameters but can be easily extended to make it support any authorization mechanism (MembershipProvider, ASP.NET Identity, custom userbase on an external DBMS or file, etc.) by removing the custom constructor and modifying the OnActionExecuting method IF block accordingly.
For additional info, you can also read this post I wrote on my blog.
Here's the way that has worked for me. It's a little foot work but it will make IIS and MVC3 behave a lot more like all the other Basic Http authentication systems, like Apache...
Step 1.
Make sure "Basic Authentication" is installed for IIS.
( Example: Control Panel -> Programs and Features -> Turn Windows features on or off )
*I'm using Windows 7 at the moment and am not sure the exact path. [GOOGLE: installing basic authentication in IIS] should get you close.
Step 2.
Make sure Basic Authentication is enabled under your site. If you had to install this in the previous step you need to make sure you reset the IIS service and that all the app pools actually went down.
Step 3.
(Note: I am using MVC3, and feel this should work in most models, including ASP.Net, without a lot of fuss.)
In your project you will need to add the following classes:
public class ServicePrincipal : IPrincipal { // This answers the "What am I allowed to do" question
// In real life, this guy will contain all your user info
// and you can put what ever you like and retrieve it
// later via the HttpContext, on your application side.
// Some fun with casting will be required.
public static IPrincipal Default {
get {
return new ServicePrincipal {
Identity = new ServiceIdentity {
AuthenticationType = "Test",
IsAuthenticated = true,
Name = "Basic"
}
};
}
}
public IIdentity Identity { get; set; }
public bool IsInRole(string role) {
// If you want to use role based authorization
// e.g. [Authorize(Roles = "CoolPeople")]
// This is the place to do it and you can do
// anything from load info from a db or flat file
// or simple case statement...though that would
// be silly.
return true;
}
}
public class ServiceIdentity : IIdentity { // This answers the "Who Am I" Question
public string AuthenticationType { get; set; }
public bool IsAuthenticated { get; set; }
public string Name { get; set; }
}
public class ServiceModule : IHttpModule { // This is the module for IIS
public void Init(HttpApplication context) {
context.AuthenticateRequest += this.BasicAuthenticationRequest;
}
public void BasicAuthenticationRequest(object sender, EventArgs e) {
HttpApplication app = sender as HttpApplication;
if( !ServiceProvider.Authenticate(app.Context) ) {
// Total FAIL!
}
}
public void Dispose() {
// Clean up the mess, if needed.
}
}
public class ServiceProvider {
public static bool Authenticate( HttpContext context ) {
// For the example we are going to create a nothing user
// say he is awesome, pass him along through and be done.
// The heavy lifting of the auth process will go here
// in the real world.
HttpContext.Current.User = ServicePrincipal.Default;
return true;
}
}
Step 3a. [edit]
Here's the different libs you'll be "using"
using System.Security.Principal;
using System.Web;
Just wanted to throw those in. I hate it when folks leave them out. :)
Step 4.
Add the following to your web config. Please note I am including the surrounding structure, for example the "configuration" tag... It's just a road map, if you already have a "configuration" tag don't add the other or IIS gets upset with you.
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="ServiceCredentialModule" type="{Namespace}.ServiceModule"/>
</modules>
</system.webServer>
<configuration>
Please note that the Namespace in {Namespace}.ServiceModule is the Namespace you put the classes from Step 3 into.
...and that's pretty much it.