public IHttpActionResult Login([FromBody] LoginViewModel info) { #region Parameters validation if (info == null) { info = new LoginViewModel(); Validate(info); } #endregion if (!ModelState.IsValid) { return(BadRequest(ModelState)); } #region Find account information in database // Hash the password first. var hashedPassword = _encryptionService.InitMd5(info.Password).ToLower(); // Find accounts from db var accounts = UnitOfWork.RepositoryStudent.Search(); accounts = accounts.Where(x => x.Username.Equals(info.Username, StringComparison.InvariantCultureIgnoreCase) && x.Status == MasterItemStatus.Active); // // Find account availability. // var account = await accounts.FirstOrDefaultAsync(); // if (account == null) // return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.NotFound, // HttpMessages.AccountNotFound)); // Find roles related to user. var userRoles = UnitOfWork.RepositoryUserRole.Search(); var userRolesPairs = (from user in accounts from userRole in userRoles where userRole.StudentId == user.Id select new { User = user, UserRole = userRole }).ToList(); var profile = new LoginModel { User = userRolesPairs.Select(x => x.User).FirstOrDefault(), Roles = userRolesPairs.Select(x => x.UserRole.RoleId).ToList() }; // User is not found in database. if (profile.User == null) { return(ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.NotFound, HttpMessages.AccountNotFound))); } // Check user role if (profile.Roles == null || profile.Roles.Count < 1) { return(ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.Forbidden, HttpMessages.NoRoleAssignedToUser))); } // Check Password if (!hashedPassword.Equals(profile.User.Password, StringComparison.InvariantCultureIgnoreCase)) { return(ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.NotFound, HttpMessages.AccountNotFound))); } #region Token initialization // Initiate claim. //var generic = new Generic(account); var claims = new Dictionary <string, string> { { nameof(profile.User.Id), profile.User.Id.ToString() }, { nameof(profile.User.Username), profile.User.Username }, { nameof(profile.User.Fullname), profile.User.Fullname } }; var token = new TokenViewModel(); token.Code = IdentityService.EncodeJwt(claims, IdentityService.JwtSecret); token.Expiration = SystemTimeService.DateTimeUtcToUnix(DateTime.Now.AddSeconds(IdentityService.JwtLifeTime)); token.LifeTime = IdentityService.JwtLifeTime; // Convert user information to profile. var cachedProfile = AutoMapper.Mapper.Map <Database.Models.Entities.Student, ProfileViewModel>(profile.User); cachedProfile.Roles = profile.Roles; // Push information back to cache. _profileCacheService.Add(cachedProfile.Id, cachedProfile); #endregion return(Ok(token)); #endregion }
// This method gets called by the runtime. Use this method to add services // to the container. public void ConfigureServices(IServiceCollection services) { // Basic config services.AddSingleton(Configuration); services.AddOptions(); var backendRoutes = new BackendRoutes(); Configuration.GetSection("BackendRoutes").Bind(backendRoutes); services.AddSingleton(backendRoutes); var stackdriverOptions = new StackdriverOptions(); Configuration.Bind("Stackdriver", stackdriverOptions); services.AddSingleton(stackdriverOptions); // Set up the shared DataProtection keystorage when running on Google Cloud. if (!Environment.IsDevelopment()) { services.AddDataProtection() // Store keys in Cloud Storage so that multiple instances // of the web application see the same keys. .PersistKeysToGoogleCloudStorage( Configuration["DataProtection:Bucket"], Configuration["DataProtection:Object"]) // Protect the keys with Google KMS for encryption and fine- // grained access control. .ProtectKeysWithGoogleKms( Configuration["DataProtection:KmsKeyName"]); } // Set up user event tracking. IUserEventsService userEventsService; if (!Environment.IsDevelopment()) { userEventsService = new UserEventsService(stackdriverOptions); } else { userEventsService = new NullUserEventsService(); } services.AddSingleton(userEventsService); // App services var restClient = new RestClient(); services.AddSingleton <IRestClient>(restClient); var timerFactory = new SystemTimerFactory(new NullLogger()); // Use NullLogger until we get problems. services.AddSingleton <ITimerFactory>(timerFactory); var timeService = new SystemTimeService(); services.AddSingleton <ITimeService>(timeService); var tokenService = new Auth0TokenService(restClient, timerFactory, LoggerFactory.CreateLogger <Auth0TokenService>()); var auth0Client = new Auth0Client(tokenService, restClient); services.AddSingleton <IAuth0Client>(auth0Client); _accountService = new AccountService(userEventsService, LoggerFactory, timeService); services.AddSingleton(_accountService); var timeLogServie = new TimeLogService(timeService, userEventsService); services.AddSingleton <ITimeLogService>(timeLogServie); // Paddle config. var paddleClient = new PaddleClient(Configuration["Paddle:VendorId"], Configuration["Paddle:VendorAuthCode"], restClient, LoggerFactory); services.AddSingleton <IPaddleClient>(paddleClient); services.AddSingleton <IPaddleWebhookSignatureVerifier>(new PaddleWebhookSignatureVerifier()); // Configure Google App Engine logging if (!Environment.IsDevelopment()) { services.Configure <StackdriverOptions>(Configuration.GetSection("Stackdriver")); services.AddGoogleExceptionLogging(options => { options.ProjectId = stackdriverOptions.ProjectId; options.ServiceName = stackdriverOptions.ServiceName; options.Version = stackdriverOptions.Version; }); services.AddGoogleTrace(options => { options.ProjectId = stackdriverOptions.ProjectId; options.Options = TraceOptions.Create(bufferOptions: BufferOptions.NoBuffer()); }); } services.AddEntityFrameworkNpgsql() .AddDbContext <MainDbContext>() .BuildServiceProvider(); // ======= Authentication config ======= services.Configure <CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.Authority = "https://maesure.auth0.com/"; options.Audience = "https://maesure.com/api/"; }) .AddCookie(options => { options.LoginPath = "/api/auth/login"; options.LogoutPath = "/api/auth/logout"; options.SlidingExpiration = true; options.ExpireTimeSpan = TimeSpan.FromDays(90); options.Cookie.Expiration = TimeSpan.FromDays(90); options.Cookie.SameSite = SameSiteMode.Lax; // OAuth login will not work with "strict" options.Cookie.IsEssential = true; }) .AddOpenIdConnect("Auth0", options => { // Set the authority to your Auth0 domain options.Authority = $"https://{Configuration["Auth0:Domain"]}"; // Configure the Auth0 Client ID and Client Secret options.ClientId = Configuration["Auth0:ClientId"]; options.ClientSecret = Configuration["Auth0:ClientSecret"]; // Set response type to code options.ResponseType = "code"; // Configure the scope options.Scope.Clear(); options.Scope.Add("openid email profile"); // Set the callback path, so Auth0 will call back to http://localhost:5000/callback // Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard // WARNING: here, "callback" is not some placeholder URL. ASP.NET expects the user to be // sent litteral "/callback" URL. Do not change this. options.CallbackPath = new PathString("/callback"); // Configure the Claims Issuer to be Auth0 options.ClaimsIssuer = "Auth0"; options.Events = new OpenIdConnectEvents { // handle the logout redirection OnRedirectToIdentityProviderForSignOut = (context) => { var logoutUri = $"https://{Configuration["Auth0:Domain"]}/v2/logout?client_id={Configuration["Auth0:ClientId"]}"; var postLogoutUri = context.Properties.RedirectUri; if (!string.IsNullOrEmpty(postLogoutUri)) { if (postLogoutUri.StartsWith("/")) { // transform to absolute var request = context.Request; postLogoutUri = request.Scheme + "://" + request.Host + postLogoutUri; } logoutUri += $"&returnTo={ Uri.EscapeDataString(postLogoutUri)}"; } context.Response.Redirect(logoutUri); context.HandleResponse(); return(Task.CompletedTask); }, OnRedirectToIdentityProvider = (context) => { // Check if we need to tell Auth0 explicitly which // connection to use. var properties = context.Properties; var connection = properties.GetString("connection"); if (connection != null) { context.ProtocolMessage.SetParameter("connection", connection); } return(Task.CompletedTask); }, OnTokenValidated = async(context) => { // Ensure that the user exists in our database. using (var db = new MainDbContext()) { // Get the Auth0 user details. var userClaims = context.SecurityToken.Claims; var auth0Id = userClaims.FirstOrDefault(c => c.Type == "sub").Value; _log.LogInformation($"Ensuring account exists for '{auth0Id}'"); // See if there's a temp account session here. var cookies = context.HttpContext.Request.Cookies; cookies.TryGetValue(PublicWebProxyController.VisitorSessionKey, out var sessionId); await _accountService.EnsureAccountEsists(db, auth0Id, sessionId); _log.LogInformation($"Finished login for '{auth0Id}'"); } }, };
public async Task <IHttpActionResult> Login([FromBody] LoginViewModel info) { #region Parameters validation if (info == null) { info = new LoginViewModel(); Validate(info); } #endregion if (!ModelState.IsValid) { return(BadRequest(ModelState)); } #region Find account information in database // Hash the password first. var hashedPassword = _encryptionService.InitMd5(info.Password).ToLower(); var accounts = UnitOfWork.RepositoryStudent.Search(); accounts = accounts.Where(x => x.Username.Equals(info.Username) && x.Password.ToLower() == hashedPassword && x.Status == MasterItemStatus.Active); // Find account availability. var account = await accounts.FirstOrDefaultAsync(); if (account == null) { return(ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.Forbidden, HttpMessages.AccountNotFound))); } #region Token initialization // Initiate claim. var generic = new Generic(account); var claims = new Dictionary <string, string> { { nameof(account.Id), account.Id.ToString() }, { nameof(account.Username), account.Username }, { nameof(account.Fullname), account.Fullname } }; var token = new TokenViewModel(); token.Code = IdentityService.EncodeJwt(claims, IdentityService.JwtSecret); token.Expiration = SystemTimeService.DateTimeUtcToUnix(DateTime.Now.AddSeconds(IdentityService.JwtLifeTime)); token.LifeTime = IdentityService.JwtLifeTime; #endregion return(Ok(token)); #endregion }