M$ AspNet.WebApi 2.2

Testé avec mono current sous Debian Sid:

l'import AspNet.WebApi 2.2
This commit is contained in:
Paul Schneider 2016-01-04 01:40:41 +01:00
commit 1f64b48966
97 changed files with 7890 additions and 9323 deletions

View file

@ -26,14 +26,493 @@ using System.Web.Security;
using System.Web.Profile;
using Yavsc.Helpers;
using System.Collections.Specialized;
using Yavsc.App_Start;
using Microsoft.Owin.Security;
using Microsoft.AspNet.Identity;
using Yavsc.Models.Identity;
using Microsoft.Owin.Security.Cookies;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Security.Claims;
using Microsoft.Owin.Security.OAuth;
using Yavsc.Providers;
using System.Security.Cryptography;
using System.Web;
using Microsoft.AspNet.Identity.Owin;
namespace Yavsc.ApiControllers
{
/// <summary>
/// Account controller.
/// </summary>
public class AccountController : YavscController
[Authorize]
[RoutePrefix("api/Account")]
public class AccountController : ApiController
{
private const string LocalLoginProvider = "Local";
private ApplicationUserManager _userManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; private set; }
// GET api/Account/UserInfo
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("UserInfo")]
public UserInfoViewModel GetUserInfo()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
return new UserInfoViewModel
{
Email = User.Identity.GetUserName(),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
}
// POST api/Account/Logout
[Route("Logout")]
public IHttpActionResult Logout()
{
Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return Ok();
}
// GET api/Account/ManageInfo?returnUrl=%2F&generateState=true
[Route("ManageInfo")]
public async Task<ManageInfoViewModel> GetManageInfo(string returnUrl, bool generateState = false)
{
IdentityUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user == null)
{
return null;
}
List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();
foreach (IdentityUserLogin linkedAccount in user.Logins)
{
logins.Add(new UserLoginInfoViewModel
{
LoginProvider = linkedAccount.LoginProvider,
ProviderKey = linkedAccount.ProviderKey
});
}
if (user.PasswordHash != null)
{
logins.Add(new UserLoginInfoViewModel
{
LoginProvider = LocalLoginProvider,
ProviderKey = user.UserName,
});
}
return new ManageInfoViewModel
{
LocalLoginProvider = LocalLoginProvider,
Email = user.UserName,
Logins = logins,
ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
};
}
// POST api/Account/ChangePassword
[Route("ChangePassword")]
public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
model.NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST api/Account/SetPassword
[Route("SetPassword")]
public async Task<IHttpActionResult> SetPassword(SetPasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST api/Account/AddExternalLogin
[Route("AddExternalLogin")]
public async Task<IHttpActionResult> AddExternalLogin(AddExternalLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken);
if (ticket == null || ticket.Identity == null || (ticket.Properties != null
&& ticket.Properties.ExpiresUtc.HasValue
&& ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow))
{
return BadRequest("External login failure.");
}
ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity);
if (externalData == null)
{
return BadRequest("The external login is already associated with an account.");
}
IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey));
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST api/Account/RemoveLogin
[Route("RemoveLogin")]
public async Task<IHttpActionResult> RemoveLogin(RemoveLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result;
if (model.LoginProvider == LocalLoginProvider)
{
result = await UserManager.RemovePasswordAsync(User.Identity.GetUserId());
}
else
{
result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(model.LoginProvider, model.ProviderKey));
}
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// GET api/Account/ExternalLogin
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
{
if (error != null)
{
return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
}
if (!User.Identity.IsAuthenticated)
{
return new ChallengeResult(provider, this);
}
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
if (externalLogin.LoginProvider != provider)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
return new ChallengeResult(provider, this);
}
ApplicationUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
externalLogin.ProviderKey));
bool hasRegistered = user != null;
if (hasRegistered)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
Authentication.SignIn(properties, oAuthIdentity, cookieIdentity);
}
else
{
IEnumerable<Claim> claims = externalLogin.GetClaims();
ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
Authentication.SignIn(identity);
}
return Ok();
}
// GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true
[AllowAnonymous]
[Route("ExternalLogins")]
public IEnumerable<ExternalLoginViewModel> GetExternalLogins(string returnUrl, bool generateState = false)
{
IEnumerable<AuthenticationDescription> descriptions = Authentication.GetExternalAuthenticationTypes();
List<ExternalLoginViewModel> logins = new List<ExternalLoginViewModel>();
string state;
if (generateState)
{
const int strengthInBits = 256;
state = RandomOAuthStateGenerator.Generate(strengthInBits);
}
else
{
state = null;
}
foreach (AuthenticationDescription description in descriptions)
{
ExternalLoginViewModel login = new ExternalLoginViewModel
{
Name = description.Caption,
Url = Url.Route("ExternalLogin", new
{
provider = description.AuthenticationType,
response_type = "token",
client_id = Startup.PublicClientId,
redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri,
state = state
}),
State = state
};
logins.Add(login);
}
return logins;
}
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST api/Account/RegisterExternal
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var info = await Authentication.GetExternalLoginInfoAsync();
if (info == null)
{
return InternalServerError();
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
result = await UserManager.AddLoginAsync(user.Id, info.Login);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
UserManager.Dispose();
}
base.Dispose(disposing);
}
#region Helpers
private IAuthenticationManager Authentication
{
get { return Request.GetOwinContext().Authentication; }
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
{
return InternalServerError();
}
if (!result.Succeeded)
{
if (result.Errors != null)
{
foreach (string error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
if (ModelState.IsValid)
{
// No ModelState errors are available to send, so just return an empty BadRequest.
return BadRequest();
}
return BadRequest(ModelState);
}
return null;
}
private class ExternalLoginData
{
public string LoginProvider { get; set; }
public string ProviderKey { get; set; }
public string UserName { get; set; }
public IList<Claim> GetClaims()
{
IList<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, ProviderKey, null, LoginProvider));
if (UserName != null)
{
claims.Add(new Claim(ClaimTypes.Name, UserName, null, LoginProvider));
}
return claims;
}
public static ExternalLoginData FromIdentity(ClaimsIdentity identity)
{
if (identity == null)
{
return null;
}
Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);
if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer)
|| String.IsNullOrEmpty(providerKeyClaim.Value))
{
return null;
}
if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer)
{
return null;
}
return new ExternalLoginData
{
LoginProvider = providerKeyClaim.Issuer,
ProviderKey = providerKeyClaim.Value,
UserName = identity.FindFirstValue(ClaimTypes.Name)
};
}
}
private static class RandomOAuthStateGenerator
{
private static RandomNumberGenerator _random = new RNGCryptoServiceProvider();
public static string Generate(int strengthInBits)
{
const int bitsPerByte = 8;
if (strengthInBits % bitsPerByte != 0)
{
throw new ArgumentException("strengthInBits must be evenly divisible by 8.", "strengthInBits");
}
int strengthInBytes = strengthInBits / bitsPerByte;
byte[] data = new byte[strengthInBytes];
_random.GetBytes(data);
return HttpServerUtility.UrlTokenEncode(data);
}
}
#endregion
/// <summary>
/// Register the specified model.
@ -41,7 +520,7 @@ namespace Yavsc.ApiControllers
/// <param name="model">Model.</param>
[Authorize ()]
[ValidateAjaxAttribute]
public HttpResponseMessage Register ([FromBody] RegisterClientModel model)
public void Register ([FromBody] RegisterClientModel model)
{
if (ModelState.IsValid) {
@ -51,7 +530,7 @@ namespace Yavsc.ApiControllers
ModelState.AddModelError ("Register",
"Since you're not member of Admin or FrontOffice groups, " +
"you cannot ask for a pre-approuved registration");
return DefaultResponse ();
return ;
}
MembershipCreateStatus mcs;
var user = Membership.CreateUser (
@ -86,7 +565,6 @@ namespace Yavsc.ApiControllers
break;
}
}
return DefaultResponse ();
}
/// <summary>
@ -96,7 +574,8 @@ namespace Yavsc.ApiControllers
[ValidateAjax]
public void ResetPassword (LostPasswordModel model)
{
if (ModelState.IsValid) {
if (ModelState.IsValid)
{
StringDictionary errors;
MembershipUser user;
YavscHelpers.ValidatePasswordReset (model, out errors, out user);
@ -107,6 +586,10 @@ namespace Yavsc.ApiControllers
}
}
/// <summary>
/// Login the specified model.
/// </summary>
/// <param name="model">Model.</param>
[ValidateAjax]
public void Login(LoginModel model)
{

View file

@ -41,14 +41,15 @@ namespace Yavsc.ApiControllers
/// <summary>
/// Authorization denied.
/// </summary>
public class AuthorizationDenied : HttpRequestException {
public class AuthorizationDenied : HttpResponseException {
/// <summary>
/// Initializes a new instance of the Yavsc.ApiControllers.AuthorizationDenied class.
/// </summary>
/// <param name="msg">Message.</param>
public AuthorizationDenied(string msg) : base(msg)
public AuthorizationDenied() : base(HttpStatusCode.Forbidden)
{
}
}

View file

@ -66,7 +66,7 @@ namespace Yavsc.ApiControllers
public void RemoveTitle(string user, string title) {
if (Membership.GetUser ().UserName != user)
if (!Roles.IsUserInRole("Admin"))
throw new AuthorizationDenied (user);
throw new AuthorizationDenied ();
BlogManager.RemoveTitle (user, title);
}
@ -103,9 +103,13 @@ namespace Yavsc.ApiControllers
public async Task<HttpResponseMessage> PostFile(long id) {
if (!(Request.Content.Headers.ContentType.MediaType=="multipart/form-data"))
throw new HttpRequestException ("not a multipart/form-data request");
if (id == 0) {
throw new NotImplementedException ();
}
BlogEntry be = BlogManager.GetPost (id);
if (be.Author != Membership.GetUser ().UserName)
throw new AuthorizationDenied ("b"+id);
throw new AuthorizationDenied ();
string root = HttpContext.Current.Server.MapPath("~/bfiles/"+id);
DirectoryInfo di = new DirectoryInfo (root);
if (!di.Exists) di.Create ();
@ -116,14 +120,11 @@ namespace Yavsc.ApiControllers
// Read the form data.
await Request.Content.ReadAsMultipartAsync(provider) ;
var invalidChars = Path.GetInvalidFileNameChars();
foreach (string fkey in provider.BodyPartFileNames.Keys)
foreach (var file in provider.FileData)
{
string filename = provider.BodyPartFileNames[fkey];
string filename = file.LocalFileName;
Trace.WriteLine(filename);
string nicename = HttpUtility.UrlDecode(fkey) ;
if (fkey.StartsWith("\"") && fkey.EndsWith("\"") && fkey.Length > 2)
nicename = fkey.Substring(1,fkey.Length-2);
string nicename = file.Headers.ContentDisposition.FileName ;
nicename = new string (nicename.Where( x=> !invalidChars.Contains(x)).ToArray());
nicename = nicename.Replace(' ','_');
var dest = Path.Combine(root,nicename);
@ -217,7 +218,7 @@ namespace Yavsc.ApiControllers
throw new HttpRequestException ("not a multipart/form-data request");
BlogEntry be = BlogManager.GetPost (id);
if (be.Author != Membership.GetUser ().UserName)
throw new AuthorizationDenied ("post: "+id);
throw new AuthorizationDenied ();
string root = HttpContext.Current.Server.MapPath("~/bfiles/"+id);
DirectoryInfo di = new DirectoryInfo (root);
if (!di.Exists) di.Create ();
@ -231,11 +232,11 @@ namespace Yavsc.ApiControllers
var invalidChars = Path.GetInvalidFileNameChars();
List<string> bodies = new List<string>();
foreach (string fkey in provider.BodyPartFileNames.Keys)
foreach (var file in provider.FileData)
{
string filename = provider.BodyPartFileNames[fkey];
string filename = file.LocalFileName;
string nicename=fkey;
string nicename= file.Headers.ContentDisposition.FileName;
var filtered = new string (nicename.Where( x=> !invalidChars.Contains(x)).ToArray());
FileInfo fi = new FileInfo(filtered);

View file

@ -29,6 +29,7 @@ using Yavsc.Model.Circles;
using Yavsc.Model.Calendar;
using System.Web.Http.Routing;
using System.Collections.Generic;
using Yavsc.Model.Maps;
namespace Yavsc.ApiControllers
@ -44,7 +45,8 @@ namespace Yavsc.ApiControllers
new YaEvent () {
Description = "Test Descr",
Title = "Night club special bubble party",
Location = new Position () {
Location = new Location () {
Address = "2 bd A Bri",
Longitude = 0,
Latitude = 0
}
@ -52,7 +54,7 @@ namespace Yavsc.ApiControllers
new YaEvent () {
Title = "Test2",
Photo = "http://bla/im.png",
Location = new Position () {
Location = new Location () {
Longitude = 0,
Latitude = 0
}
@ -60,7 +62,7 @@ namespace Yavsc.ApiControllers
new YaEvent () {
Description = "Test Descr",
Title = "Night club special bubble party",
Location = new Position () {
Location = new Location () {
Longitude = 0,
Latitude = 0
}
@ -68,7 +70,7 @@ namespace Yavsc.ApiControllers
new YaEvent () {
Title = "Test2",
Photo = "http://bla/im.png",
Location = new Position () {
Location = new Location () {
Longitude = 0,
Latitude = 0
}

View file

@ -0,0 +1,53 @@
//
// AccountController.cs
//
// Author:
// Paul Schneider <paul@pschneider.fr>
//
// Copyright (c) 2015 GNU GPL
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using Owin;
using Microsoft.Owin.Extensions;
namespace Yavsc.ApiControllers
{
public class ChallengeResult : IHttpActionResult
{
public ChallengeResult(string loginProvider, ApiController controller)
{
LoginProvider = loginProvider;
Request = controller.Request;
}
public string LoginProvider { get; set; }
public HttpRequestMessage Request { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
Request.GetOwinContext().Authentication.Challenge(LoginProvider);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.RequestMessage = Request;
return Task.FromResult(response);
}
}
}

View file

@ -129,7 +129,7 @@ namespace Yavsc.ApiControllers
string user = Membership.GetUser ().UserName;
CircleBase current = CircleManager.DefaultProvider.Get (circle.Id);
if (current.Owner != user)
throw new AuthorizationDenied ("Your not owner of circle at id "+circle.Id);
throw new AuthorizationDenied ();
CircleManager.DefaultProvider.UpdateCircle (circle);
}

View file

@ -84,10 +84,7 @@ namespace Yavsc.ApiControllers
if (est.Client != username)
if (!Roles.IsUserInRole("Admin"))
if (!Roles.IsUserInRole("FrontOffice"))
throw new AuthorizationDenied (
string.Format (
"Auth denied to eid {1} for:{2}",
id, username));
throw new AuthorizationDenied ();
return est;
}

View file

@ -55,17 +55,6 @@ namespace Yavsc.ApiControllers
pr.Save ();
}
}
/// <summary>
/// Defaults the response.
/// </summary>
/// <returns>The response.</returns>
protected HttpResponseMessage DefaultResponse()
{
return ModelState.IsValid ?
Request.CreateResponse (System.Net.HttpStatusCode.OK) :
Request.CreateResponse (System.Net.HttpStatusCode.BadRequest,
ValidateAjaxAttribute.GetErrorModelObject (ModelState));
}
}
}