OWIN OpenID的连接授权失败授权安全控制器/行动 [英] OWIN OpenID connect authorization fails to authorize secured controller / actions

查看:1134
本文介绍了OWIN OpenID的连接授权失败授权安全控制器/行动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的一个项目,第三方供应商将作为一个基础的OAuth2授权服务器。一个Asp.net MVC 5基于客户端,将用户发送到授权服务器进行身份验证(使用登录/密码)和auth服务器会返回一个访问令牌返回给客户端的MVC。到资源服务器(API)的任何进一步的调用将使用访问令牌进行。



要做到这一点,我使用Microsoft.Owin.Security.OpenIdConnect和UseOpenIdConnectAuthentication扩展。我能够成功重定向并从auth服务器的访问令牌,但客户端不创建一个身份验证cookie。每次我尝试访问安全网页,我得到的回调页面访问令牌。



我缺少的是在这里吗? 。我当前的代码如下



有担保的控制器动作:

 命名空间MvcWebApp.Controllers 
{
公共类SecuredController:控制器
{
// GET:安全
[授权]
公众的ActionResult指数()
{
返回查看((用户为ClaimsPrincipal).Claims);
}
}
}



启动类:

 公共类启动
{
公共无效配置(IAppBuilder应用程序)
{
app.SetDefaultSignInAsAuthenticationType(ClientCookie);

app.UseCookieAuthentication(新CookieAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType =ClientCookie,
CookieName = CookieAuthenticationDefaults.CookiePrefix + ClientCookie,
ExpireTimeSpan = TimeSpan.FromMinutes(5)
});

// ******* ***********
//方法1:的responseType =id_token令牌
// ************ ************
app.UseOpenIdConnectAuthentication(新OpenIdConnectAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,
SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
管理局=https://thirdparty.com.au/oauth2,
客户端Id =_Th4GVMa0JSrJ8RKcZrzbcexk5ca,
ClientSecret =a3GVJJbLHkrn9nJRj3IGNvk5eGQa,
RedirectUri =HTTP://mvcwebapp.local/,
的responseType =id_token标记,
范围=OpenID的,

配置=新OpenIdConnectConfiguration
{
AuthorizationEndpoint =https://thirdparty.com.au/oauth2/authorize,
TokenEndpoint =https://thirdparty.com.au/oauth2/token,
UserInfoEndpoint =https://thirdparty.com.au/oauth2/userinfo,
},

=通知新OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = N =>
{
VAR令牌= n.ProtocolMessage.AccessToken;

//坚持饼干
访问令牌,如果(!string.IsNullOrEmpty(令牌))
{
n.AuthenticationTicket.Identity.AddClaim(
新的索赔(的access_token令牌));
}

返回Task.FromResult(0);
},

AuthenticationFailed =通知=>
{
如果(string.Equals(notification.ProtocolMessage.Error,ACCESS_DENIED,StringComparison.Ordinal))
{
notification.HandleResponse();

notification.Response.Redirect(/);
}

返回Task.FromResult<对象>(NULL);
}
}
});

// ******* ***********
//方法2:的responseType =代码
// ************ ******************************
//app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
// {
// AuthenticationMode = AuthenticationMode.Active,
// AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,
// SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
//管理局=https://开头thirdparty.com.au/oauth2,
//客户端Id =_Th4GVMa0JSrJ8RKcZrzbcexk5ca,
// ClientSecret =a3GVJJbLHkrn9nJRj3IGNvk5eGQa,
// RedirectUri =HTTP://mvcwebapp.local/ ,
//的responseType =暗码,
//范围=OpenID的,

//配置=新OpenIdConnectConfiguration
// {
// AuthorizationEndpoint =https://thirdparty.com.au/oauth2/authorize,
// TokenEndpoint =https://thirdparty.com.au/oauth2/token,
/ / UserInfoEndpoint =https://thirdparty.com.au/oauth2/userinfo,
//},

//通知=新OpenIdConnectAuthenticationNotifications
// {
// AuthorizationCodeReceived =异步(通知)=>
// {
//使用(VAR的客户=新的HttpClient())
// {
//无功配置=等待notification.Options.ConfigurationManager.GetConfigurationAsync(通知。 Request.CallCancelled);
// VAR要求=新HttpRequestMessage(HttpMethod.Get,configuration.TokenEndpoint);
// request.Content =新FormUrlEncodedContent(新字典<字符串,字符串>
// {
// {OpenIdConnectParameterNames.ClientId,notification.Options.ClientId}
/ / {OpenIdConnectParameterNames.ClientSecret,notification.Options.ClientSecret}
// {OpenIdConnectParameterNames.Code,notification.ProtocolMessage.Code}
// {OpenIdConnectParameterNames.GrantType,authorization_code},
// {OpenIdConnectParameterNames.ResponseType,令牌},
// {OpenIdConnectParameterNames.RedirectUri,notification.Options.RedirectUri}
//});

// VAR响应=等待client.SendAsync(请求,notification.Request.CallCancelled);
// response.EnsureSuccessStatusCode();

//无功负载= JObject.Parse(等待response.Content.ReadAsStringAsync());

// //添加访问令牌返回ClaimsIdentity,使其更容易检索。
// notification.AuthenticationTicket.Identity.AddClaim(新索赔(
//类型:OpenIdConnectParameterNames.AccessToken,
//值:payload.Value<串GT;(OpenIdConnectParameterNames.AccessToken))) ;
//}
//}
//}

//});

}
}


解决方案

TL; DR:使用的responseType =id_token标记,它应该工作



在OpenID的连接, RESPONSE_TYPE =标记不被视为合法值:的 http://openid.net/specs/openid-connect-core-1_0.html#Authentication



有时为了向后兼容的原因实施, RESPONSE_TYPE =标记不是由MSFT开发的OIDC中间件的支持:一个异常始终抛出时,没有 id_token 被连接的OpenID提供者返回(这也排除了有效的代码流量)。你可以找到这个其他 SO发布的更多信息。



(备注:在 SecurityTokenValidated ,你要替换 n.AuthenticationTicket =新AuthenticationTicket(...)使用OIDC中间件创建票证:这不是推荐的方法,将导致 ClaimsIdentity 缺少必要的索赔应考虑删除的分配和简单地添加新的索赔像你这样做。在的access_token 索赔)


I am working on a project where a third party provider will act as an Oauth2 based Authorization Server. An Asp.net MVC 5 based client which will send the user to the authorization server to authenticate (using login / password) and the auth server will return an access token back to the MVC client. Any further calls to resource servers (APIs) will be made using the access token.

To achieve this I am using Microsoft.Owin.Security.OpenIdConnect and the UseOpenIdConnectAuthentication extension. I am able to successfully redirect and get the access token from the auth server but the client is not creating an Authentication Cookie. Every time I try to access a secured page, I get the callback page with access token.

What am I missing here? My current code is below.

The secured controller action:

namespace MvcWebApp.Controllers
{    
    public class SecuredController : Controller
    {
        // GET: Secured
        [Authorize]
        public ActionResult Index()
        {
            return View((User as ClaimsPrincipal).Claims);
        }
    }
}

The Startup Class:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType("ClientCookie");

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            AuthenticationType = "ClientCookie",
            CookieName = CookieAuthenticationDefaults.CookiePrefix + "ClientCookie",
            ExpireTimeSpan = TimeSpan.FromMinutes(5)
        });

        // ***************************************************************************
        // Approach 1 : ResponseType = "id_token token"
        // ***************************************************************************
        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,
            SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
            Authority = "https://thirdparty.com.au/oauth2",
            ClientId = "_Th4GVMa0JSrJ8RKcZrzbcexk5ca",
            ClientSecret = "a3GVJJbLHkrn9nJRj3IGNvk5eGQa",
            RedirectUri = "http://mvcwebapp.local/",
            ResponseType = "id_token token",
            Scope = "openid",

            Configuration = new OpenIdConnectConfiguration
            {
                AuthorizationEndpoint = "https://thirdparty.com.au/oauth2/authorize",
                TokenEndpoint = "https://thirdparty.com.au/oauth2/token",
                UserInfoEndpoint = "https://thirdparty.com.au/oauth2/userinfo",
            },

            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                SecurityTokenValidated = n =>
                {
                    var token = n.ProtocolMessage.AccessToken;

                    // persist access token in cookie
                    if (!string.IsNullOrEmpty(token))
                    {
                        n.AuthenticationTicket.Identity.AddClaim(
                            new Claim("access_token", token));
                    }

                    return Task.FromResult(0);
                },

                AuthenticationFailed = notification =>
                {
                    if (string.Equals(notification.ProtocolMessage.Error, "access_denied", StringComparison.Ordinal))
                    {
                        notification.HandleResponse();

                        notification.Response.Redirect("/");
                    }

                    return Task.FromResult<object>(null);
                }
            }
        });

        // ***************************************************************************
        // Approach 2 : ResponseType = "code"
        // ***************************************************************************
        //app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        //{
        //    AuthenticationMode = AuthenticationMode.Active,
        //    AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,
        //    SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
        //    Authority = "https://thirdparty.com.au/oauth2",
        //    ClientId = "_Th4GVMa0JSrJ8RKcZrzbcexk5ca",
        //    ClientSecret = "a3GVJJbLHkrn9nJRj3IGNvk5eGQa",
        //    RedirectUri = "http://mvcwebapp.local/",
        //    ResponseType = "code",
        //    Scope = "openid",

        //    Configuration = new OpenIdConnectConfiguration
        //    {
        //        AuthorizationEndpoint = "https://thirdparty.com.au/oauth2/authorize",
        //        TokenEndpoint = "https://thirdparty.com.au/oauth2/token",
        //        UserInfoEndpoint = "https://thirdparty.com.au/oauth2/userinfo",
        //    },

        //    Notifications = new OpenIdConnectAuthenticationNotifications
        //    {
        //        AuthorizationCodeReceived = async (notification) =>
        //        {
        //            using (var client = new HttpClient())
        //            {
        //                var configuration = await notification.Options.ConfigurationManager.GetConfigurationAsync(notification.Request.CallCancelled);                                        
        //                var request = new HttpRequestMessage(HttpMethod.Get, configuration.TokenEndpoint);
        //                request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
        //                {
        //                    {OpenIdConnectParameterNames.ClientId, notification.Options.ClientId},
        //                    {OpenIdConnectParameterNames.ClientSecret, notification.Options.ClientSecret},
        //                    {OpenIdConnectParameterNames.Code, notification.ProtocolMessage.Code},
        //                    {OpenIdConnectParameterNames.GrantType, "authorization_code"},
        //                    {OpenIdConnectParameterNames.ResponseType, "token"},
        //                    {OpenIdConnectParameterNames.RedirectUri, notification.Options.RedirectUri}
        //                });

        //                var response = await client.SendAsync(request, notification.Request.CallCancelled);
        //                response.EnsureSuccessStatusCode();

        //                var payload = JObject.Parse(await response.Content.ReadAsStringAsync());

        //                // Add the access token to the returned ClaimsIdentity to make it easier to retrieve.
        //                notification.AuthenticationTicket.Identity.AddClaim(new Claim(
        //                    type: OpenIdConnectParameterNames.AccessToken,
        //                    value: payload.Value<string>(OpenIdConnectParameterNames.AccessToken)));
        //            }
        //        }
        //    }

        //});

    }
}             

解决方案

TL;DR: use ResponseType = "id_token token" and it should work.

In OpenID Connect, response_type=token is not considered as a legal value: http://openid.net/specs/openid-connect-core-1_0.html#Authentication.

Sometimes implemented for backward compatibility reasons, response_type=token is not supported by the OIDC middleware developed by MSFT: an exception is always thrown when no id_token is returned by the OpenID Connect provider (which also excludes the valid code flow). You can find more information on this other SO post.

(remark: in SecurityTokenValidated, you're replacing the ticket created by the OIDC middleware using n.AuthenticationTicket = new AuthenticationTicket(...): it's not the recommended approach and will result in a ClaimsIdentity missing the essential claims. You should consider removing the assignation and simply add new claims like you do for the access_token claim)

这篇关于OWIN OpenID的连接授权失败授权安全控制器/行动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆