Example #1
0
        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
        }
Example #2
0
        // 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
        }