I have this working code:
public AspNetAuthorizer Authoriser { get; set; }
protected async void Page_Load(object sender, EventArgs e)
{
var currentUser = v2.Membership.Functions.GetLoggedInAsUser();
Authoriser = v3.Twitter.Auth.GetUserAuthorizer(currentUser.UserID,
v3.Arcade.Settings.TwitterScirraArcadeAppAppName, v3.Arcade.Settings.TwitterScirraArcadeAppConsumerKey,
v3.Arcade.Settings.TwitterScirraArcadeAppConsumerSecret);
if (!Page.IsPostBack && Request.QueryString["oauth_token"] != null)
{
await Authoriser.CompleteAuthorizeAsync(Request.Url);
var credentials = Authoriser.CredentialStore;
v3.Twitter.Auth.SaveAuthorisationDetails(currentUser.UserID,
v3.Arcade.Settings.TwitterScirraArcadeAppAppName, credentials.OAuthToken, credentials.OAuthTokenSecret,
credentials.ScreenName);
}
else
{
if (!Authoriser.CredentialStore.HasAllCredentials())
{
await Authoriser.BeginAuthorizeAsync(new Uri("https://127.0.0.1/newarcade/twitterpopup.aspx"));
}
}
}
If no authorisation is stored, it redirects to Twitter authentication request. Otherwise, it continues on the page.
The problem I am facing is when a user revokes access to the app via their Twitter account, how can I detect on this page that the app no longer has permission to post Tweets for the user and needs reauthorising?
You can query VerifyCredentials:
try
{
var verifyResponse =
await
(from acct in twitterCtx.Account
where acct.Type == AccountType.VerifyCredentials
select acct)
.SingleOrDefaultAsync();
if (verifyResponse != null && verifyResponse.User != null)
{
User user = verifyResponse.User;
Console.WriteLine(
"Credentials are good for {0}.",
user.ScreenNameResponse);
}
}
catch (TwitterQueryException tqe)
{
Console.WriteLine(tqe.Message);
}
If that fails, you can force authorization by dropping the user's credential keys and authorizing with only ConsumerKey/ConsumerSecret. That will bring the user to the Twitter page to authorize your app again. Then you can re-save those user credentials, in case they've changed.
Related
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> UploadExcel(HttpPostedFileBase upload)
{
//Check File code here//
DriveItem item = null;
string Secret1 = "secret";
string Client1 = "clientid";
string Tenant1 = "tenantid";
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(Client1)
.WithAuthority(AzureCloudInstance.AzurePublic, Tenant1)
.WithRedirectUri("uri")
.WithClientSecret(Secret1)
.Build();
AuthorizationCodeProvider authProvider1 = new AuthorizationCodeProvider(confidentialClientApplication);
GraphServiceClient graphClient = new GraphServiceClient(authProvider1);
using (Stream file1 = upload.InputStream)
{
try
{
item = await graphClient.Me.Drive.Items["id_of_a_file"]
.Content
.Request()
.PutAsync<DriveItem>(file1);
}
catch (Exception ex)
{
//Handle Exception
}
}
if (item == null)
{
//Tell user
}
return RedirectToAction("ActionName");
}
Also Redirect URI is always null no matter what I do.
I have searched elsewhere but could not find a solution. This is a Web application. User login is handled by us. Users upload files to Company's OneDrive Account. All the necessary permissions and admin consent are granted. Still error is not resolved.
I am finally able to send Email confirmation on my MVC 5 Application
The user now receives an email and the EmailConfirmed field is updated from False to True. However, the user is still able to login without confirming the email.
My question is how can I restrict access until user has confirmed email link
Below is my ConfirmEmail Method.
// GET: /Account/ConfirmEmail
[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string Token, string Email)
{
ApplicationUser user = this.UserManager.FindById(Token);
if (user != null)
{
if (user.Email == Email)
{
user.EmailConfirmed = true;
await UserManager.UpdateAsync(user);
//await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home", new { ConfirmedEmail = user.Email });
}
else
{
return RedirectToAction("Confirm", "Account", new { Email = user.Email });
}
}
else
{
return RedirectToAction("Confirm", "Account", new { Email = "" });
}
}
[AllowAnonymous]
public ActionResult Confirm(string Email)
{
ViewBag.Email = Email; return View();
}
Thank you everyone for reading.
Ceci
----- UPDATE ------
I added the code below to the /Account/Login Controller
var user = await UserManager.FindByNameAsync(model.UserName);
if(user != null){
if (!await UserManager.IsEmailConfirmedAsync(user.UserName)) {
return View("ErrorNotConfirmed");
}
}
But its returning an error. UserId not Found.
I am posting this code in case someone needs it.
Basically I replaced the code above with this code:
var userid = UserManager.FindByEmail(model.UserName).Id;
if (!UserManager.IsEmailConfirmed(userid))
{
return View("EmailNotConfirmed");
}
It works beautifully now.
Ive used couple of days trying to figugure out how to return an error to angular ajax request to web api.
in my js AccountController i have a login method:
$scope.Login = function () {
AccountService.Login($scope.UserData.LoginName, $scope.UserData.Password).success(function (account) {
$scope.UserData = account;
}).error(function () {
console.log("failed");
});
};
and in web api i have folowing:
public Account Login(string loginName, string password)
{
var emptyAccount = new Account();
password = Encrypt(password);
var account = db.Accounts.FirstOrDefault(c=>c.Password == password && c.LoginName == loginName);
if (account == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
acount.Password = "";
return account;
}
The problem is that i throw a new HttpResponseException which fire off and dont return anything back to ajax. How do i fix this?
Normally, in this case it is the error handler that will get triggered.
.error(function () {
alert("login failed");
}
This is where you could handle the error.
Also you probably want to return 401 Unauthorized in this case instead of 404. Also in general it is considered bad practice to throw exceptions in cases where you can handle it gracefully:
public HttpResponseMessage Login(string loginName, string password)
{
var emptyAccount = new Account();
password = Encrypt(password);
var account = db.Accounts.FirstOrDefault(c => c.Password == password && c.LoginName == loginName);
if (account == null)
{
return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "unauthorized");
}
acount.Password = "";
return Request.CreateResponse(HttpStatusCode.OK, account);
}
When you sending the data, and it's hit the servers, it will return header 200 OK because it's already hit your controller, even when your controller code is throw error (in later process).
so, if you want to know what error that thrown, I will create AccountResponse Dto into that, and introduce new Error field in that like so:
public class AccountResponse()
{
public Account account { get; set;}
public string ErrorMessage { get; set; }
}
and then on the controller:
public AccountResponse Login(string loginName, string password)
{
var emptyAccount = new Account();
password = Encrypt(password);
var account = db.Accounts.FirstOrDefault(c=>c.Password == password && c.LoginName == loginName);
if (account == null)
{
return new AccountResponse(){ ErrorMessage = Response.ResponseCodes.something;
}
AccountResponse.account = account;
AccountResponse.account.Password = "";
return AccountResponse;
}
**Login** in *spring security*, when user is disabled, i can't know the password is wrong or not.
please,tell me how.
[AbstractUserDetailsAuthenticationProvider][1]
in spring security:
AbstractUserDetailsAuthenticationProvider.authenticate(){
// (1) check disabled, if disabled, ***throw exception***
preAuthenticationChecks.check(user);
// (2)check password
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
Heading
(1)`public void check(UserDetails user) {
if (!user.isAccountNonLocked()) {
logger.debug("User account is locked");
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
"User account is locked"), user);
}
if (!user.isEnabled()) {
logger.debug("User account is disabled");
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
"User is disabled"), user);
}
if (!user.isAccountNonExpired()) {
logger.debug("User account is expired");
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
"User account has expired"), user);
}
}`
(2)`protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
Object salt = null;
if (this.saltSource != null) {
salt = this.saltSource.getSalt(userDetails);
}
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails);
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails);
}
}`
}
}
One way to handle this is to add a redirect in the login page
AuthenticationException ex = ((AuthenticationException) request.getSession().getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION));
if(ex instanceof DisabledException){
//Send redirect
}
I have a MVC app where I have a User class and the user can also impersonate another user(Admin users only).
So I have this code below that authenticates the request and instantiates my version of a User class.
It then tries to get the impersonated user from the Session object but Session is not available in this method in the global.asax.
Hope this makes sense.
How else could I do this?
My question I guess is at what point in the global.asax methods do you get access to Session object for each request?
protected void Application_OnAuthenticateRequest(object sender, EventArgs e)
{
IMylesterService service = ObjectFactory.GetInstance<IMylesterService>();
if (Context.User != null)
{
if (Context.User.Identity.IsAuthenticated)
{
User user = service.GetUser(Context.User.Identity.Name);
if (user == null)
throw new ApplicationException("Context.user.Identity.name is not a recognized user");
User impersonatedUser = (User)this.Session["ImpersonatedUser"];
if (impersonatedUser == null)
user.ImpersonatedUser = user;
else
user.ImpersonatedUser = impersonatedUser;
System.Threading.Thread.CurrentPrincipal = Context.User = user;
return;
}
}
User guest = service.GetGuestUser();
guest.ImpersonatedUser = guest;
System.Threading.Thread.CurrentPrincipal = Context.User = guest;
}
Try creating an authorization filter:
public class CustomAuthorizationFilter : AuthorizeAttribute
{
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
// perform your authorization here
// full access to HttpContext and session
}
}
You can then apply this attribute to your controllers. Ideally you'd have a base controller that all other controllers inherit from and you could apply the attribute at the class level on that controller. Then all of your requests would be authorized and apply the impersonation as you have coded above.
Session will not be available during AuthenticateRequest: What you will need to do is tag the required information to the Identity.userData; so for example if you where using forms authentication do the following:
void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.User != null)
{
if (Context.User.Identity.IsAuthenticated)
{
// retrieve the value
var id = (FormsIdentity)Context.User.Identity;
var myvalue = id.Ticket.UserData; // "Here you are"
}
}
}
For sign in using forms you will need to write a custom cookie:
MVC -> class FormsAuthenticationService : IFormsAuthenticationService
public static void SetAuthenticationCookie(HttpContextBase context, FormsAuthenticationTicket ticket)
{
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName)
{
Value = FormsAuthentication.Encrypt(ticket),
Secure = FormsAuthentication.RequireSSL,
Domain = FormsAuthentication.CookieDomain,
HttpOnly = true,
Expires = DateTime.Now.AddMinutes(15)
};
if (!context.Request.IsSecureConnection && FormsAuthentication.RequireSSL)
{
throw new HttpException("Ticket requires SSL.");
}
context.Response.Cookies.Add(cookie);
}
public static FormsAuthenticationTicket CreateTicket(HttpContextBase context, string emailAddress, string userData, bool persist)
{
return new FormsAuthenticationTicket(1, emailAddress, DateTime.Now, DateTime.Now.AddMinutes(15), persist, userData, FormsAuthentication.FormsCookiePath);
}
Finally in SignIn you would now create the required ticket by calling CreateTicket(...), and then you would write it out by SetAuthenticationCookie(...).
public void SignIn(string userName, string password)
{
if(CheckUserValid(userName,password, out string email))
{
var ticket = CreateTicket(email, "Here you are", true);
SetAuthenticationCookie(HttpContext.Current.Base(), ticket);
}
}
I have never used it, but assume that session state is assigned during the AcquireRequestState:
public void Init(HttpApplication context)
{
context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
}
I had this same issue of needing to access session in global.asax and finally solved it by moving my code into the AcquireRequestState handler, which happens after the authentication is passed.
protected void Application_AcquireRequestState(Object sender, EventArgs e)
{
if (Request.IsAuthenticated && Context.Session != null)
{
// access Context.Session
}
}
This fires a lot and the current context does not always have a valid session object, hence the check.
EDIT: Had to add the check for IsAuthenticated too -- was getting a null error when logged out. Works great now.