Showing posts with label authentication. Show all posts
Showing posts with label authentication. Show all posts

Monday, October 8, 2018

Spring secure endpoint with only client credentials (Basic)

Leave a Comment

I have oauth2 authorization server with one custom endpoint (log out specific user manually as admin) I want this endpoint to be secured with rest client credentials (client id and secret as Basic encoded header value), similar to /oauth/check_token.

This endpoint can be called only from my resource server with specific scope.

  1. I need to check if the client is authenticated.
  2. I would like to be able to add @PreAuthorize("#oauth2.hasScope('TEST_SCOPE')")on the controller`s method.

I could not find any docs or way to use the Spring`s mechanism for client authentication check.

EDIT 1

I use java config not an xml one

1 Answers

Answers 1

@PreAuthorize("#oauth2.hasScope('TEST_SCOPE')") On the controller method should be sufficiënt. If the client is not authenticated, no scope is available and the scope check will fail.

If you want, you can use the Spring Security expression @PreAuthorize("isAuthenticated()") to check if a client is authenticated: https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#el-common-built-in

You could also configure the HttpSecurity instead of working with @PreAuthorize

Read More

Saturday, September 15, 2018

GCP Authentication: RefreshError

Leave a Comment

In order to round-trip test mail sending code in our GCP backend I am sending an email to a GMail inbox and attempting to verify its arrival. The current mechanism for authentication to the GMail API is fairly standard, pasted from the GMail API documentation and embedded in a function:

def authenticate():     """Authenticates to the Gmail API using data in credentials.json,     returning the service instance for use in queries etc."""     store = file.Storage('token.json')     creds = store.get()     if not creds or creds.invalid:         flow = client.flow_from_clientsecrets(CRED_FILE_PATH, SCOPES)         creds = tools.run_flow(flow, store)     service = build('gmail', 'v1', http=creds.authorize(Http()))     return service 

CRED_FILE_PATH points to a downloaded credentials file for the service. The absence of the token.json file triggers its re-creation after an authentication interaction via a browser window, as does the token's expiry.

This is an integration test that must run headless (i.e. with no interaction whatsoever). When re-authentication is required the test currently raises an exception when the authentication flow starts to access sys.argv, which means it sees the arguments to pytest!

I've been trying to find out how to authenticate reliably using a mechanism that does not require user interaction (such as an API key). Nothing in the documentation or on Stackoverflow seems to answer this question.

A more recent effort uses the keyfile from a service account with GMail delegation to avoid the interactive Oauth2 flows.

def authenticate():     """Authenticates to the Gmail API using data in g_suite_access.json,     returning the service instance for use in queries etc."""     main_cred = service_account.Credentials.from_service_account_file(         CRED_FILE_PATH, scopes=SCOPES)     # Establish limited credential to minimise any damage.     credentials = main_cred.with_subject(GMAIL_USER)     service = build('gmail', 'v1', credentials=credentials)     return service 

On trying to use this service with

        response = service.users().messages().list(userId='me',                                     q=f'subject:{subject}').execute() 

I get:

google.auth.exceptions.RefreshError:   ('unauthorized_client: Client is unauthorized to retrieve access tokens using this method.',    '{\n "error": "unauthorized_client",\n "error_description": "Client is unauthorized to retrieve access tokens using this method."\n}') 

I get the feeling there's something fundamental I'm not understanding.

1 Answers

Answers 1

The service account needs to be authorized or it cant access the emails for the domain.

"Client is unauthorized to retrieve access tokens using this method"

Means that you have not authorized it properly; check Delegating domain-wide authority to the service account

Source: Client is unauthorized to retrieve access tokens using this method Gmail API C#

Read More

Wednesday, September 12, 2018

How to combine the windows authentication and JWT with .Net Core 2.1

Leave a Comment

I have tried to use the windows authentication and JWT together with .NET Core 2.1.

I have following startup settings of the authentication:

services.AddAuthentication(options =>                 {                     options.DefaultAuthenticateScheme = IISDefaults.AuthenticationScheme;                     options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;                 })                 .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>             {                 options.TokenValidationParameters = new TokenValidationParameters                 {                     ValidateIssuer = true,                     ValidateAudience = true,                     ValidateLifetime = true,                     ValidateIssuerSigningKey = true,                      ValidIssuer = "Test",                     ValidAudience = "Test",                     IssuerSigningKey = JwtSecurityKey.Create("677efa87-aa4d-42d6-adc8-9f866e5f75f7")                 };                  options.Events = new JwtBearerEvents()                 {                     OnAuthenticationFailed = OnAuthenticationFailed                 };             }); 

IIS settings:

"iisSettings": {     "windowsAuthentication": true,      "anonymousAuthentication": true,      ..   } 

I have tried following code snippet to create the JWT token with windows authentication:

[Route("api/[controller]")]     [ApiController]     [Authorize(AuthenticationSchemes = "Windows")]     public class AuthController : ControllerBase     {         [HttpPost("token")]         public IActionResult Token()         {             //Setup claims             var claims = new[]             {                 new Claim(ClaimTypes.Name, User.Identity.Name),                 //Add additional claims             };              //Read signing symmetric key             var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("677efa87-aa4d-42d6-adc8-9f866e5f75f7"));             var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);              //Create a token             var token = new JwtSecurityToken(                 issuer: "Test",                 audience: "Test",                 claims: claims,                 expires: DateTime.Now.AddMinutes(30),                 signingCredentials: creds);              //Return signed JWT token             return Ok(new             {                 token = new JwtSecurityTokenHandler().WriteToken(token)             });         }     } 

And in another controller I need use only JWT authentication:

[Route("api/[controller]")]     [ApiController]     [Authorize(AuthenticationSchemes = "Bearer")]     public class ProductController : ControllerBase     {         [HttpGet]         public IActionResult Get()         {             var userName = User.Identity.Name;              var claims = User.Claims.Select(x => new { x.Type, x.Value });              return Ok(new { userName, claims });         }     } 

If the JWT token is expired then I correctly received the response code 401 but I still get the dialog in the browser for putting the credentials.

How can I configure the windows authentication only for a part when I want to create the JWT token and disable response which is responsible for showing the browser dialog with credentials? How to correctly combine these things?

1 Answers

Answers 1

This answer might help: https://stackoverflow.com/a/51055082/1212994

You need to ensure, that you NOT setting Authorization: Bearer HTTP header when you trying to use Windows Auth. The key point here is how "Windows Auth" actually works. Let's look how it works with browser for example.

Read More

Monday, September 3, 2018

FormsAuthenticationTicket: how to keep the user logged in after the browser has been closed?

Leave a Comment

I'm logging the user this way, using FormsAuthenticationTicket:

[HttpPost] [ValidateAntiForgeryToken] public ActionResult Login(LoginViewModel loginView) {     if (ModelState.IsValid)     {         if (Membership.ValidateUser(loginView.Email, loginView.Password))         {             var user = (CustomMembershipUser)Membership.GetUser(loginView.Email, false);             if (user != null)             {                 CustomPrincipalSerializeModel userSerializeModel = new CustomPrincipalSerializeModel()                 {                     ID = user.ID,                     FirstName = user.FirstName,                     LastName = user.LastName,                     RoleName = user.Roles.Select(r => r.RoleName).ToList()                 };                  string userData = JsonConvert.SerializeObject(userSerializeModel);                 DateTime expirationDate = loginView.KeepMeLoggedIn ? DateTime.Now.AddMonths(12) : DateTime.Now.AddMinutes(15);                 FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, user.UserName, DateTime.Now, expirationDate, false, userData);                  HttpCookie faCookie = new HttpCookie("CookieFA", FormsAuthentication.Encrypt(authTicket));                 Response.Cookies.Add(faCookie);             }              return RedirectToAction("Index", "Home");         }     }      ModelState.AddModelError("", "Login Error");      return View("Login"); } 

But even if I set loginView.KeepMeLoggedIn to true (which should keep the login for 1 year), when I close the browser and I reopen the website, the user is logged off.

How can I keep it logged in also when I close the browser?

1 Answers

Answers 1

First, you need to set the 5th parameter of the FormsAuthenticationTicket constructor 'isPersistent' to true.

Then I would add change the code to this:

var faCookie = new HttpCookie("CookieFA", FormsAuthentication.Encrypt(authTicket)); if (authTicket.IsPersistent) {     faCookie.Expires = authTicket.Expiration; } Response.Cookies.Add(faCookie); 

And if you also want to honor what's configured in web.config, you can add this extra code (optional):

var faCookie= new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(authTicket)); faCookie.Path = FormsAuthentication.FormsCookiePath;  if (FormsAuthentication.RequireSSL) {     faCookie.Secure = true; }  if (FormsAuthentication.CookieDomain != null) {     faCookie.Domain = FormsAuthentication.CookieDomain; } ... 
Read More

Saturday, August 25, 2018

how to authenticate user with email only passport.js?

Leave a Comment

I am trying to authenticate my user with specific flow.

User will enter email for signup and user will be logged in immediately to the account and I will send email confirmation link, with that link user could update password and login to the account.

But i am stuck

I am confused how to signup and login with email only

route.js

  app.post('/get_started', (req, res) => {          let {email} = req.body;          let isEmail = emailValidator(email);          // i will save the user email and try to login          if(isEmail){              passport.authenticate('local',{ successRedirect: '/dashboard', failureRedirect: '/' })          }     }) 

Startegy.js

import LocalStrategy from 'passport-local'  export default passport => {      passport.use('local',new LocalStrategy( (email, done) => {          console.log(email,'Inside Passport')      }));  } 

2 Answers

Answers 1

Here is an example which additionaly uses sequelize and bcrypt:

route.js:

app.post('/get_started', passport.authenticate('local'), (req, res) => {      // Do stuff after successful login here } 

Strategy.js:

passport.use(     'local',     new LocalStrategy(         {usernameField: 'email'},         (email, passwordCleartext, done) =>              User.findOne({where: {email: email}})                 .then(user =>                      !user ?                         done('Unauthorized', false, {message: 'Incorrect email or password.'}) :                         bcrypt.compare(passwordCleartext, user.password)                             .then(res =>                                  res ?                                      done(null, user, {message: 'Logged In Successfully'}) :                                     done('Unauthorized', false, {message: 'Incorrect email or password.'}))                             )                 .catch(() => done('Unauthorized', false, {message: 'Incorrect email or password.'}))     ) ); 

Answers 2

Before I demonstrate how to achieve what you have ask for, I would strongly suggest against re-engineering the login and signup systems.These systems have been around since forever and for the most cases, it is best to stick to the traditional ways of doing so.

With that said,

To achieve the functionality that user can login using just email, you can use the passport-custom module which will let you write your own logic to login user.

Register the strategy:

passport.use(     "my-custom-strategy",     new CustomStrategy(function(req, callback) {         const email = req.body.email;         User.exists(email).then(exists => {             const info = {};             if (exists) {                 // user has already entered password,                 // redirect to some page and where user can enter the password                 info.passwordRequired = true;             } else {                 // user has not entered password,                 // add the user to db                 // send the link and let them login for now                 info.sendEmailLink = true;             }             return callback(null, { email }, info);         });         callback(null, user);     }) ); 

I assume that User.exists(email) method is available which will return the promise that will either resolve to true or false based based of whether the email exists. The info object will be used in the controller to implement the actual logic.

app.use("/get_started", (req, res, next) => {     let { email } = req.body;     let isEmail = emailValidator(email);     // i will save the user email and try to login     if (isEmail) {         passport.authenticate("my-custom-strategy", (err, user, info) => {             if (info.passwordRequired) {                 // you can use custom cookie to set the user.email                 // and access it later to fully authenticate the user                 // using the email and password                 res.redirect("/enter_password");             } else if (info.sendEmailLink) {                 // logic to send the email                 // once the email sent, redirect to dashboard                 res.redirect("/dashboard");             }         })(req, res, next);     } }); 
Read More

Friday, August 24, 2018

Laravel : Increase time on second time login attempts

Leave a Comment

Currently five login attempts blocks user for 1 minute and its working fine with the following code :

if ($this->hasTooManyLoginAttempts($request)) {     $this->fireLockoutEvent($request);     return $this->sendLockoutResponse($request); } 

What i want is that, When a user gets unblocked again after the first attempts, On the second attempts the block time should increase to 3 minutes.

I searched around, But could not found anything, Is there any way around it ?

3 Answers

Answers 1

I would suggest you try the following code. Please ask if anything is unclear.

$minutes = 3; $key = $this->throttleKey($request); $rateLimiter = $this->limiter();  if ($this->hasTooManyLoginAttempts($request)) {      $attempts = $rateLimiter->attempts($key);      if ($attempts > 1) {         $attempts === 2 && $rateLimiter->clear($key);         $this->decayMinutes = ($attempts - 1) * $minutes;         $attempts === 2 && $this->incrementLoginAttempts($request);         $this->incrementLoginAttempts($request);     }      $this->fireLockoutEvent($request);     return $this->sendLockoutResponse($request); } 

Code for incremental blocking:

$minutes = 3; $key = $this->throttleKey($request); $rateLimiter = $this->limiter();  if ($this->hasTooManyLoginAttempts($request)) {      $attempts = $rateLimiter->attempts($key);     $rateLimiter->clear($key);     $this->decayMinutes = $attempts === 1 ? 1 : ($attempts - 1) * $minutes;      for ($i = 0; $i < $attempts; $i++) {         $this->incrementLoginAttempts($request);     }      $this->fireLockoutEvent($request);     return $this->sendLockoutResponse($request); } 

Code for incremental blocking with cache:

$minutes = 3; $key = $this->throttleKey($request); $rateLimiter = $this->limiter();  if ($this->hasTooManyLoginAttempts($request)) {      $attempts = $rateLimiter->attempts($key);     $rateLimiter->clear($key);      $reflection = new \ReflectionClass($rateLimiter);     $property = $reflection->getProperty('cache');     $property->setAccessible(true);     $cache = $property->getValue($rateLimiter);      $blockMinutes = $attempts === 1 ? 1 : ($attempts - 1) * $minutes;     $cache->add($key.':timer', $rateLimiter->availableAt($blockMinutes * 60), $blockMinutes);     $added = $cache->add($key, 0, $blockMinutes);     $hits = (int) $cache->increment($key, $attempts);     if (! $added && $hits === 1) {         $cache->put($key, 1, $blockMinutes);     }     $property->setAccessible(false);      $this->fireLockoutEvent($request);     return $this->sendLockoutResponse($request); } 

Answers 2

I think you need to set property in LoginController:

public $decayMinutes = 1; // minutes to lockout 

Also you can controll numbers of attempts:

public $maxAttempts = 5; 

For more information you can investigate: trait AuthenticatesUsers - which has method "login" and code from your description. And this trait uses another trait: "ThrottlesLogins" -> this traits has method named "decayMinutes". It returns number of minutes.

Hope it will help you!

Answers 3

I think laravel default doesn't provide what your need, So you need to save in (cache, session or database) if user had blocked once on your own, and increase decayMinutes as you want.

if ($this->hasTooManyLoginAttempts($request)) {     if(Cache::has($this->throttleKey($request))){         $this->decayMinutes = 3;     }      Cache::put($this->throttleKey($request), true);     $this->fireLockoutEvent($request);      return $this->sendLockoutResponse($request); } 
Read More

Thursday, July 5, 2018

Multicast Websockets in Spring Boot

Leave a Comment

Context

First time working with websockets in spring. My application involves one type of user (CHAP) providing their current location to all others who are subscribed (USR) (and are authorized to subscribe to this info)

I'm reading through the documentation and have found this section which I believe holds my solution, but I'm just not 100% sure how exactly it works, and would love someone with a stronger understanding to put it in other words. I've seen similar questions on stack overflow but the solutions feel too specific (though this could just be my own lack of understanding).

The Problem

One CHAP per topic who can publish their location to the topic. Users can subscribe to any topics their authorized to subscribe to.

So essentially:

  • Multiple topics at a variable endpoint (something like /{route_id}/location )

  • Users can subscribe to these topics and receive updates when they are available

  • Users with the CHAP role can publish to one topic. (i.e. each CHAP has a {route_id} they can publish to.

  • Users with USR role can listen to multiple topics that they are part of (i.e. each USR has several routes they can listen for updates on)

This is similar problem to having multiple chat rooms, which is the common example for websockets. However all examples I can find either have static chat room names, single chat rooms, or can only target messages to one user (not a group)

Current Code

@MessageMapping("/chaperone/location") // chaperone sends data to here @SendTo("/{route_id}/location") // users can listen in on this public BusModel updateLocation(@DestinationVariable long route_id, BusModel busModel) {     return routeService.updateBusLocation(busModel); } 

My thinking here is that chaperones post to that url, and all users subscribed to their route will get an update.

Thanks!

1 Answers

Answers 1

This might be a solution, but no configuration is supplied. Will give this a try and hope for the best then fill in the details here if it works.

Read More

Wednesday, May 23, 2018

Make Web API authentication return 401 instead of redirect to login page

Leave a Comment

I have Web API with OWIN Authentication in Web MVC. I'm using <authentication> in Web.Config for my Web MVC so it's redirecting to login page.

<authentication mode="Forms">     <forms name="WEB.AUTH" loginUrl="~/login" domain="" protection="All"      timeout="43200" path="/" requireSSL="false" slidingExpiration="true" /> </authentication> 

I'm using [System.Web.Http.Authorize] attribute to authorize my Web API. But somehow, the API redirecting to login page same like my MVC app because of above configuration.

what I want to do is keep redirecting function for the Web MVC but returning 401 for Web API. How can I achieve this? should I create a custom authorization attribute for Web API?

--EDIT--

I found the answer from this post SuppressDefaultHostAuthentication in WebApi.Owin also suppressing authentication outside webapi

So I just add a few lines into my Startup.cs. I had all my controllers configured with a "api" prefix route.

HttpConfiguration config = new HttpConfiguration(); //..some OWIN configuration app.Map("/api", inner => {   inner.UseWebApi(config); }); 

make sure you put app.Map() after Web Api Configuration lines. Otherwise, it will give error to MVC application.

3 Answers

Answers 1

Create a custom AuthorizeAttribute:

public class MyAuthorizeAttribute : AuthorizeAttribute {     protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)     {         actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Unauthorized");     } } 

If you in the future skip the web.config stuff and use owin to setup your authentication, you could in your Startup.cs do:

var provider = new CookieAuthenticationProvider(); var originalHandler = provider.OnApplyRedirect; provider.OnApplyRedirect = context => {     if (!context.Request.Uri.LocalPath.StartsWith(VirtualPathUtility.ToAbsolute("~/api")))     {         context.RedirectUri = new Uri(context.RedirectUri).PathAndQuery;         originalHandler.Invoke(context);     } };  app.UseCookieAuthentication(new CookieAuthenticationOptions {     AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,     CookieName = FormsAuthentication.FormsCookieName,     LoginPath = new PathString("/Account/LogOn"),     ExpireTimeSpan = TimeSpan.FromMinutes(240),     Provider = provider }); 

Answers 2

This is what worked for me.

Creating a custom attribute:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class NoRedirectAuthorizeAttribute : AuthorizeAttribute {             protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)     {         actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);     } } 

Using the attribute in your controller:

    [HttpDelete]     [NoRedirectAuthorizeAttribute(Roles = "Admin")]     [Route("api/v3/thingstodelete/{id=id}")]     public IHttpActionResult DeleteThingToDelete(Guid id)     {       //delete code     } 

Here are just overriding the HandleUnauthorizedRequest method of the AuthorizeAttribute. So, instead of sending a redirect (304) to the login page, we send Forbidden(403) HTTP status code.

Answers 3

In order to change the way IIS behaves based on a convention defined by URL, you want to branch your OWIN pipeline. You can do this by using IApplicationBuilder.Map. Assuming a static config:

public void Configure(IApplicationBuilder app) {     ...     app.Map("/api", HandleWebApiRequests);     ... }  private static void HandleWebApiRequests(IApplicationBuilder app) {     app.UseWebApi(config); } 

The Map method branches the pipeline to the HandleWebApiRequests method based on an URL that begins with "/api".

This should cause 401 errors to behave like they are supposed to and simply return 401 with no redirect.

Read More

Saturday, March 31, 2018

AngularJS token authentication with sliding expiration in state transitions with ui-router version 1.x

Leave a Comment

In our application we have a requirement that user should be logged in for a certain amount of time which is configurable by system admin, say 10 minutes. We have another requirement that the when user navigates to different parts of the app, this time should be refreshed and set back to that configured amount.

Our application is written in AngularJS and we use ui-router for routing, So when user navigates between different states, time to be logged out gets updated.

The back-end is written with .NET and we use jwt tokens for authentication, Token has a field named expiration. In the beginning of each request we check if the token is not expired.

I have a problem that I don't know how to tell the server that it should update the token expiration time, I am using ui-router version 1 and it has some hooks for doing server side things before state transitions, I ended up with something like this:

  $transitions.onBefore({       to: "*"   }, function(trans) {            // update the client ui, and also tell the server to update      // the timeout in the serverside and database       return authService.refreshToken();   }); 

But I am uncertain about this approach being correct, I couldn't find a good solutions for such problem in a REST architecture, I would be very grateful if you could tell me the pros and cons of this method or point me to the right implmentation

2 Answers

Answers 1

THEORY

As far as I can see, JWT standards doesn't really tell about refresh. (https://tools.ietf.org/rfc/rfc7519.txt)

If I well understand your problem, you want somebody's token to be renewed automatically after X minutes of inactivity. I guess this approach you want is a sliding sessions.

You can see a good article about it there: https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/

The best practice in such case is not to extend the life of the token but to request a new one. You will find many articles and conventions talking about it. For security reasons, the shorter it is, the most secure it is.

Even if it is written for oauth, Here is a really good article listing different ways of token management : https://www.oauth.com/oauth2-servers/access-tokens/access-token-lifetime/


USE CASE

In your API, i would provide a refreshToken that permit to renew the token trough an HTTP request.

In you Front, I would make a service that store the last transition date, let say lastTransitionDate = new DateTime(). It will also store, the token, the refreshToken and the expiration date of the token.

Now When you have a transition,

  1. You check if the token is still valid,
  2. If the token is no more valid and if the lastTransitionDate is more than X minutes ago, you force the logout.
  3. If the token is no more valid but the lastTransitionDate is less than X minutes, then you ask for a new token thanks to your refreshToken.
  4. After all checks you reset lastTransitionDate.

The only things you need to be sure of is that, X is enough to make sure that a user won't be disconnected if he just passed some time reading some stuff on a page without triggering a transition.

Answers 2

Well, you cannot simply refresh the expiry of the token without changing it. This is because the expiry is coded in the token itself. So, when you want to change the expiry of the token, you need to change the token itself.

Being specific to your case, if you want to refresh user's timeout threshold, the server will have to create a new token for each request and send it back in response (using headers, maybe). The UI will have to store this token in the storage after the request completes.

This way, the UI will always have a latest JWT available with it. And, you don't have to make a call such as authService.refreshToken() as server automatically takes care of it, which is kind of an inefficient approach.

Also, if user is inactive for sometime (say 10 minutes), and then makes a request to the server, the JWT sent from the UI is already expired, and the server can signal the UI to expire the session.

Read More

Wednesday, February 28, 2018

AWS Cognito - Get user data after login with SignInUI

Leave a Comment

I followed the instructions at Add AWS Mobile User Sign In

The code looks like this:

public class LoginActivity extends AppCompatActivity {      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_login);          AWSMobileClient.getInstance().initialize(this, new AWSStartupHandler() {             @Override             public void onComplete(AWSStartupResult awsStartupResult) {                 SignInUI signIn = (SignInUI) AWSMobileClient.getInstance().getClient(LoginActivity.this, SignInUI.class);                 signIn.login(LoginActivity.this, MainActivity.class).execute();              }         }).execute();     } } 

My question is, how do I get the public claims for the logged in user (ie email, name etc.) so I can know who logged in? The only ways I've seen is to do it is manually which seems to require a client secret which I obviously don't have as this is a client side mobile app.

0 Answers

Read More

Wednesday, January 10, 2018

How to integrate LDAP in WPF application that consumes WCF service

Leave a Comment

I will start by describing how my application works today without LDAP. I have WPF application that consumes WCF services (authentication windows or UserName depends on users choice). This services allows communication with database.

I display to user a "Login screen" in order to allow him set her "user name" and "password" then application connects to service and consumes function that checks if UserName and Password exist in database. (see img below) enter image description here

Now I need also to integrate LDAP for authenticating user accounts against their existing systems instead of having to create another login account.

I'm bit ignorant about LDAP and confused about many things. Please excuse the possible use of wrong terminology.

I googled but I still don't have answers of many questions.

1- What is the relation between users that exist in my database table "User" and profiles that I should be created in LDAP ?

2- What is the check I should do to allow user come from LDAP to access to my application and use all functionnalities of my service ?

3- Should I have service type "LDAP" like other authentications types I have today in my application ("Windows" and "UserName") ?

4- If I want to update my application architecture described in picture above where should I add LDAP ?

1 Answers

Answers 1

Let me tell you about my experience in LDAP and Authenticate users on LDAP or DB,

I also implemented a service named Auth.svc, this service contains a method named AuthenticateAndAuthorizedUser , this is transparent for user which came from LDAP or anywhere.

1- In the other words I have a table named Users which hold users infos and one more field named ExternalPath foreign key, if it is null then UserName is in DB otherwise it is came from UserDirectory.

2- You have to hold LDAP address (in my case LDAP addresses are in ExternalPath table), All LDAP addresses are on port 389 commonly.

3- Authenticate User if is not found(with Username and Password) then Verify it over LDAP address.

4- Let me share my DB schema and Authenticate Method.

enter image description here

ExternalPath field specify user is from LDAP or not.

5- Define LDAP server and User...

enter image description here

6- While adding new user you can define LDAP for user (if you select LDAP address then don't need to get password from user)

7- But last thing is Authenticating user on LDAP and DB.

Authenticate Method is something like:

User userLogin = User.Login<User>(username, password, ConnectionString, LogFile); if (userLogin != null)     return InitiateToken(userLogin, sourceApp, sourceAddress, userIpAddress); else//Check it's LDAP path {     User user = new User(ConnectionString, LogFile).GetUser(username);     if (user != null && user.ExternalPath != null)     {         LDAPSpecification spec = new LDAPSpecification         {             UserName = username,             Password = password,             Path = user.ExternalPath.Path,             Domain = user.ExternalPath.Domain         };         bool isAthenticatedOnLDAP = LDAPAuthenticateUser(spec);      } } 

If userLogin does not exist in DB by entered UserName and Pass then we should authenticated it over related LDAP address.

First find User and Get it's ExternalPath if not null means User is on LDAP.

so the LDAPAuthenticateUser method is :

public bool LDAPAuthenticateUser(LDAPSpecification spec) {     string pathDomain = string.Format("LDAP://{0}", spec.Path);     if (!string.IsNullOrEmpty(spec.Domain))         pathDomain += string.Format("/{0}", spec.Domain);     DirectoryEntry entry = new DirectoryEntry(pathDomain, spec.UserName, spec.Password, AuthenticationTypes.Secure);     try     {         //Bind to the native AdsObject to force authentication.         object obj = entry.NativeObject;         DirectorySearcher search = new DirectorySearcher(entry);          search.Filter = "(SAMAccountName=" + spec.UserName + ")";         search.PropertiesToLoad.Add("cn");         SearchResult result = search.FindOne();         if (null == result)         {             return false;         }     }     catch (Exception ex)     {         Logging.Log(LoggingMode.Error, "Error authenticating user on LDAP , PATH:{0} , UserName:{1}, EXP:{2}", pathDomain, spec.UserName, ex.ToString());         return false;     }     return true; } 

If exception raised in LDAPAuthenticateUser means User does not exist in User Directory.

Hope will help you.

Read More

Friday, December 1, 2017

Is this cross-domain, auto-login OAuth2 SSO design correct, simple and secure?

Leave a Comment

I need to implement a cross-domain SSO solution. Let's assume I have a-site.com, b-site.com and sso-site.com.

The requirements are as follows:

  • Unlogged user clicking "Login" on a-site.com is shown a login screen hosted on sso-site.com.
  • If the user logged in as above, and subsequently visits b-site.com, they will be immediately logged in. I.e. instead of a "Login" link, we want to display their username, etc - without the need to click anything, or a quick redirect of the entire page to sso-site.com and back.

It seems to me the following scheme, using OAuth2 / OpenID Connect, with a small modification should do it:

  1. User is unlogged to a-site.com, b-site.com and sso-site.com.
  2. User goes to a-site.com, clicks "Login".
  3. Browser is redirected to sso-site.com, with return URL on a-site.com as a query string param.
  4. sso-site.com server produces a login form, sends to user's browser. User provides credentials. sso-site.com server checks credentials against DB, decides they are OK. sso-site.com responds with a redirect to the URL indicated in param in step 3. The URL has an authorization code attached as param. The redirect response also sets a session cookie (on domain sso-site.com of course).
  5. Browser receives redirect response, sends it to a-site.com. a-site.com server queries sso-site.com in the backend (not through user's browser) with the authorization code from the redirect URL. sso-site.com recognizes the authorization code, gives back an access token. If this is OpenID Connect, a-site.com also gets user info on that response. If not (plain OAuth2), it needs to make another backend call to sso-site.com to get them. a-site.com creates a user session, and on the page sent to the browser includes a session cookie (for domain a-site.com).
  6. From now on, user is obviously logged into a-site.com.
  7. User goes to b-site.com.
  8. This is where we stray from the standard OAuth2 flow. There's some Javascript in the page, which silently sends a CORS query to sso-site.com. Obviously, we have a session cookie on this request. sso-site.com recognizes the cookie and returns a new authorization code in the payload.
  9. On receiving the response, Javascript recognizes that it got an authorization code (and therefore the user is logged into SSO), so it forces a page reload, attaching the authorization code as a query string param.
  10. b-site.com server sees the authorization code in a param, so in the backend it does the same thing as a-site.com did above. This results in user being logged into b-site.com.

I should add to this that if a user is not logged into SSO, when we make the silent JS call, sso-site.com returns some payload indicating that. Then, the JS receiving that payload sets a cookie on b-site.com, whose presence means not to query sso-site.com via JS on subsequent page views.

Questions:

  • should this work (any incorrect assumptions?)
  • can it be simplified anywhere (iframes?)
  • is this secure (especially in the JS part, departing from OAuth browser redirect model)?

Many thanks! There's a lot of examples on the web for SSO, especially with OAuth2 and CAS (which has a similar flow) - but I could not find a recipe for these specific requirements: cross-domain, and with automatic login without entire page redirect (bad for latency and crawlers) on b-site.com. The closest is the Stackoverflow SSO guide (here), but they have some extra requirements I don't have.

0 Answers

Read More

Monday, November 20, 2017

In SSL/TLS communication with IIS, Certificate Request does not contain my client cert

Leave a Comment

One of my clients java/Cold Fusion application is trying to access my WCF web service endpoint using client certificate mutual authentication. We moved our wcf service to windows 2008 R2/IIS 7 machine and generated new certificate using 3rd party CA. After the change, client is getting 403.13 error. On investigation, I found that the Certificate Request does not include the new certificate in the distinguished names list. How can I configure IIS to include the client certificate in the trusted certificate list? enter image description here

1 Answers

Answers 1

You can't add trusted certificates, it's done on machine level. If you open MMC and add the certificate plugin you should be able to add it to the Trusted Root Certification Authorities on the server.

Read More

Wednesday, November 15, 2017

root cant perform listCollections command on db

Leave a Comment

I have credentials for root user and I am using those credentials to automate db backup. Main aim is to create prototype for Automated DB backup and, for simplicity, I am using root. The script (I borrowed from article) looks like as follows:

#!/bin/bash  #Force file syncronization and lock writes mongo admin -u "root" -p "root" --eval "printjson(db.fsyncLock())"  MONGODUMP_PATH="/usr/bin/mongodump" MONGO_DATABASE="mydb" #replace with your database name  TIMESTAMP=`date +%F-%H%M` S3_BUCKET_NAME="mydb" #replace with your bucket name on Amazon S3 S3_BUCKET_PATH="backup/mongo"  # Create backup $MONGODUMP_PATH -d $MONGO_DATABASE  # Add timestamp to backup mv dump mongodb-$HOSTNAME-$TIMESTAMP tar cf mongodb-$HOSTNAME-$TIMESTAMP.tar mongodb-$HOSTNAME-$TIMESTAMP  # Upload to S3 s3cmd put mongodb-$HOSTNAME-$TIMESTAMP.tar s3://$S3_BUCKET_NAME/$S3_BUCKET_PATH/mongodb-$HOSTNAME-$TIMESTAMP.tar  #Unlock database writes mongo admin -u "root" -p "root" --eval "printjson(db.fsyncUnlock())" #Delete local files #rm -rf mongodb-* 

I am getting following error:

Failed: error getting collections for database mydb: error running listCollections. Database: mydb Err: not authorized on mydb to execute command { listCollections: 1, cursor: {} }

Isnt root has all the access over all the databases? I am bit scared that I might run into situation where I am thinking to supersede something with root but It doesnt have the permission. This is the root cause of posting question. I want to avoid surprises like this in the future.

1 Answers

Answers 1

The error mentioned above was misleading for me. But my script was wrong or incomplete.

If you look at following line in my script:

$MONGODUMP_PATH -d $MONGO_DATABASE 

I am not providing any user in Mongodump command and hence the error message. If I rewrite that line something as follows:

$MONGODUMP_PATH -d $MONGO_DATABASE --authenticationDatabase "admin" -u "dbowner" -p "pwd" 

then error goes away.

Read More

Monday, November 13, 2017

Python - Manipulate and read browser from current browser

Leave a Comment

I am struggling to find a method in python which allows you to read data in a currently used web browser. Effectively, I am trying to download a massive dataframe of data on a locally controlled company webpage and implement it into a dataframe. The issue is that the website has a fairly complex authentication token process which I have not been able to bypass using Selenium using a slew of webdrivers, Requests, urllib, and cookielib using a variety of user parameters. I have given up on this front entirely as I am almost positive that there is more to the authentication process than can be achieved easily with these libraries.

However, I did manage to bypass the required tokenization process when I quickly tested opening a new tab in a current browser which was already logged in using WebBrowser. Classically, WebBrowser does not offer a read function meaning that even though the page can be opened the data on the page cannot be read into a pandas dataframe. This got me thinking I could use Win32com, open a browser, login, then run the rest of the script, but again, there is no general read ability of the dispatch for internet explorer meaning I can't send the information I want to pandas. I'm stumped. Any ideas?

I could acquire the necessary authentication token scripts, but I am sure that it would take a week or two before anything would happen on that front. I would obviously prefer to get something in the mean time while I wait for the actual auth scripts from the company.

Update: I received authentication tokens from the company, however it requires using a python package on another server I do not have access too, mostly because its an oddity that I am using Python in my department. Thus the above still applies - need a method for reading and manipulating an open browser.

1 Answers

Answers 1

1) Start browser with Selenium. 2) Script should start waiting for certain element that inform you that you got required page. 4) You can use this new browser window to logint to page. 5) Script detects that you are logged 3) Script processes page.

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC  # start webdriver chrome = webdriver.Chrome()  # initialise waiter with 300 seconds to wait. waiter = WebDriverWait(chrome , 300)  # Will wait for appear of #logout element. # I assume it shows that you are logged in. wait.until(EC.presence_of_element_located(By.ID, "logout"))  # Extract data etc. 

It might be easier to log in if you use user's profile.

options = webdriver.ChromeOptions()  options.add_argument("user-data-dir=FULL_PATH__TO_PROFILE") chrome = webdriver.Chrome(chrome_options=options) 

Maybe you should even get your page. You might have session continued so you might be already logged in

chrome.get("https://your_page_here") 
Read More

Tuesday, October 24, 2017

User not Authenticated when IdentityTokenLifetime expires

Leave a Comment

What's the correct way to refresh the IdentityToken. We're using Implicit flow.

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions     {         ClientId = ConfigurationManager.AppSettings["IdSrv.ClientId"],         Authority = ConfigurationManager.AppSettings["IdSrv.Authority"],          AuthenticationType = "MySTS",          ResponseType = "id_token token",                  //Implicit Flow           Scope = "openid name email",          RedirectUri = ConfigurationManager.AppSettings["IdSrv.RedirectUri"],         PostLogoutRedirectUri = ConfigurationManager.AppSettings["IdSrv.PostLogoutRedirectUri"],          SignInAsAuthenticationType = "OAuth Bearer",     }); 

IdentityTokenLifetime defaults to 300 (=5 minutes). When that time expires, the user is no longer authenticated. Should we return a Status 401 (and pass prompt=none), so the middleware redirects to IdentityServer3 and back again? Is there another way?

2 Answers

Answers 1

In theory:

  1. You could increase ttl of cookie, when the user is signed in by openId, and authenticate user by this cookie. If the cookie expires, then you could return 401 or make redirect to sign in again.
  2. Identity server should provide Refresh Token (by api), which used to get another access token if you need.
  3. Another thought: usually, access token provides only for limited period of time because of security reasons

Answers 2

By default the ASP.NET OIDC OWIN middleware uses the identity token lifetime as the lifetime of the cookie your app will issue. This seems to be a hang over from the WS-Federation OWIN middleware, where the incoming token is much longer lived. Since identity tokens are short lived, and typically just used once and then discarded, this behavior doesn't really work for OpenID Connect.

So you have two options:

  1. Set the identity token lifetime much higher for that client within IdentityServer (using the IdentityTokenLifetime property on the Client entity).
  2. Stop the OIDC middleware from using the identity token lifetime as the cookie lifetime. This will allow your cookie middelware to control session lifetime.

You can do this by setting the UseTokenLifetime to false:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions {     // rest of your settings     UseTokenLifetime = false } 
Read More

Monday, October 23, 2017

Gmail blocks login attempt from Python with app specific password

Leave a Comment

I'm trying to send an email from a Google account using Python's smtplib, but getting an error, and now I'm kind of at a loss. Google responds with the following: Please log in via your web browser and then try again. Learn more at https://support.google.com/mail/answer/78754.

The account has two factor authentication enabled, so I'm using an app specific password for my login. To my understanding, this should then work without enabling the setting for less secure apps, shouldn't it? I've been doing the same with another account while testing without a problem, but now I finally got the credentials for the proper account and there it won't accept the authentication.

I'm aware that there is a Python Gmail API thingy to use with OAuth, but if at all possible I don't want to include more packages and rewrite much, and I don't really want to enable the "less secure apps" setting either. Is there a way to get this working without either?

If it makes a difference, here is the code I use for sending email. As said before, this was working fine with another account, so I'm not sure if it's actually relevant.

def send_mail(to_address, subject, body):     smtp_user = "myaccount@domain.com"     smtp_password = "MyAppPasswordFromGoogle"     server = "smtp.gmail.com"     port = 587      msg = MIMEMultipart("alternative")     msg["Subject"] = subject     msg["From"] = smtp_user     msg["To"] = to_address     msg.attach(MIMEText(body, "html"))     s = smtplib.SMTP(server, port)     s.connect(server, port)     s.ehlo()     s.starttls()     s.ehlo()     s.login(smtp_user, smtp_password)     s.sendmail(smtp_user, to_address, msg.as_string())     s.quit() 

Edit: There is an interesting difference between the two accounts: on https://myaccount.google.com/lesssecureapps, my old (working) one says "this setting isn't available for accounts that have two factor authentication enabled", while the new one says "this setting is managed by your domain administrator", even though both use 2FA and it's also forced in both domains. So I suppose there is some setting that the domain admin has to change, but I don't know which one that would be.

3 Answers

Answers 1

I tried replicating exactly your case (with an account that has a two factor authentication enabled). After creating my app password, I used it in the code.

Anyway, I think your problem is this:

s = smtplib.SMTP(server, port) s.connect(server, port) 

You execute 2 times the connection.

Try with

s = smtplib.SMTP() s.connect(server, port) 

or just this

s = smtplib.SMTP(server, port) 

The entire code:

import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText   smtp_user = 'myUser@gmail.com' smtp_password = 'my16charactersAppPassword' server = 'smtp.gmail.com' port = 587 msg = MIMEMultipart("alternative") msg["Subject"] = 'Why,Oh why!' msg["From"] = smtp_user msg["To"] = "destinationUser@gmail.com" msg.attach(MIMEText('\nsent via python', 'plain')) s = smtplib.SMTP(server, port) s.ehlo() s.starttls() s.login(smtp_user, smtp_password) s.sendmail(smtp_user, "destinationUser@gmail.com", msg.as_string()) s.quit() 

Answers 2

I am just curious if you have enabled IMAP (despite of the fact that SMTP has nothing to do with IMAP)...

Here is an old list with many different solutions - Sending email through Gmail SMTP server with C#

Answers 3

Seems simple, but check to make sure Allow less secure apps is enabled.

Read More

Tuesday, October 17, 2017

Which OAuth flow should I use for my native app?

Leave a Comment

I'm developing an app using React Native and I couldn't find any tutorial to authenticate my users against my own service (I think this is called 1st party app). Users need to be able to authenticate with user/password and with their Facebook account as well.

I've been researching about it and find out that I should use Authorization Code Grant Flow which should work in this way:

  1. Create a log-in link with the app's client ID, redirect URL, and state parameters
  2. The user sees the authorization prompt and approves the request
  3. The user is redirected back to the app’s server with an auth code
  4. The app exchanges the auth code for an access token

As I understand all my redirect links should start with myapp://uri opening it in native browser. But I really don't need the step two, or do I? Why should I ask the user for permissions for the same service?

One more thing that I don't understand is that to exchange auth code for an access token I need to pass my Client ID and Client Secret. But I've read that I don't have to store client secrets in native apps since it can be compromised.

2 Answers

Answers 1

How have you initiated your react native app? Via create-react-native-app or Expo XDE or through the react-native init? If either of the first two options, Facebook Auth becomes pretty straight forward. Here's a link to Expo's Facebook Auth Docs. Here's a copy/paste example of what that would look like...

async function logIn() {   const { type, token } = await Expo.Facebook.logInWithReadPermissionsAsync('<APP_ID>', {       permissions: ['public_profile'],     });   if (type === 'success') {     // Get the user's name using Facebook's Graph API     const response = await fetch(       `https://graph.facebook.com/me?access_token=${token}`);     Alert.alert(       'Logged in!',       `Hi ${(await response.json()).name}!`,     );   } } 

This will (by default) attempt to authenticate via 'web', meaning it attempts to log in through a modal UIWebView pop up. There are other methods too, but they're only valid for stand alone apps (see behavior options).

I know you said you wanted to use your own service to do authentication, but I think it might be useful for you to at least go through the Auth0 React Native SDK Tutorial to get an idea how to secure client IDs and secrets as well as get an overall idea of what a good auth flow looks like. Then decide whether to rebuild everything yourself as your own service or whether to use theirs.

Answers 2

OAuth 2.0 is not an authentication protocol, it's for Authorization. That is why you are having problems with step 2. This might be interesting to read.

For your flow I think you have 2 options.

  1. Implicit flow, no client secret. (This would be my first choice)
  2. Use the Authorization Code Grant Flow and don't care about the secret. Do make sure you check on your server if the redirecturl is correct.
Read More

Wednesday, September 27, 2017

Authenticate users from more than two tables in laravel 5

Leave a Comment

As I know Auth::attempt is used to authenticate users from users table, but i want to authenticate another users from managers table and admin from admins table. I know there are laravel-multiauth plugin already exist. But can we create our own AuthServiceProvider for authenticating users from multiple tables..?

6 Answers

Answers 1

Try my idea if you want to. I'm expecting that different table has different users. Because it won't work if you have the same user in other tables.

  1. Choose your priority table (e.g. users)
  2. Add the condition
    • if(Auth::user(attempt(...))
    • elseif(Auth::manager(attempt(...))
    • elseif(Auth::admins(attempt(...)))

Note: Your priority table here is users, then if the user doesn't exists in that table, it will try the managers table, then if still doesn't exists, it will check the admins table, otherwise (use else) return a message error.

Other option:

Other option is to use this package sarav/laravel-multiauth. You can follow this thread. How to use authentication for multiple tables in Laravel 5 for more information.

More Reference:

https://laracasts.com/discuss/channels/general-discussion/using-laravel-auth-for-multiple-tables?page=1

Can anyone explain Laravel 5.2 Multi Auth with example

https://laracasts.com/discuss/channels/laravel/52-auth-multiple-tables?page=1

Answers 2

You could setup multiple authentication guards, with each one having a different provider. The providers define the table or model to be used.

In config/auth.php you setup the providers as follows and you also setup corresponding guards for each of those providers:

'providers' => [     'users'  => [         'driver' => 'eloquent',         'model'  => App\User::class,     ],     'managers'  => [         'driver' => 'eloquent',         'model'  => App\Manager::class,     ],     'admins'  => [         'driver' => 'eloquent',         'model'  => App\Admin::class,     ] ] 

Then you can authenticate like this:

Auth::attempt($credentials) // use default guard for simple users Auth::guard('manager')->attempt($credentials) Auth::guard('admin')->attempt($credentials) 

Check out the docs here.

Answers 3

Implement Multi Auth in Larvel 5.2

I'm considering two tables admin and users

Laravel 5.2 has a new artisan command.

php artisan make:auth 

it will generate basic login/register route, view and controller for user table.

Make a admin table as users table for simplicity.

Controller For Admin

app/Http/Controllers/AdminAuth/AuthController app/Http/Controllers/AdminAuth/PasswordController 

(note: I just copied these files from app/Http/Controllers/Auth/AuthController here)

config/auth.php

//Authenticating guards 'guards' => [     'user' =>[         'driver' => 'session',         'provider' => 'user',     ],     'admin' => [         'driver' => 'session',         'provider' => 'admin',     ], ],    //User Providers 'providers' => [     'user' => [         'driver' => 'eloquent',         'model' => App\User::class,     ],     'admin' => [         'driver' => 'eloquent',         'model' => App\Admin::class,     ] ],    //Resetting Password   'passwords' => [     'clients' => [         'provider' => 'client',         'email' => 'auth.emails.password',         'table' => 'password_resets',         'expire' => 60,     ],     'admins' => [         'provider' => 'admin',         'email' => 'auth.emails.password',         'table' => 'password_resets',         'expire' => 60,     ], ], 

route.php

Route::group(['middleware' => ['web']], function () {     //Login Routes...     Route::get('/admin/login','AdminAuth\AuthController@showLoginForm');     Route::post('/admin/login','AdminAuth\AuthController@login');     Route::get('/admin/logout','AdminAuth\AuthController@logout');      // Registration Routes...     Route::get('admin/register', 'AdminAuth\AuthController@showRegistrationForm');     Route::post('admin/register', 'AdminAuth\AuthController@register');      Route::get('/admin', 'AdminController@index');  });   

AdminAuth/AuthController.php

Add two methods and specify $redirectTo and $guard

protected $redirectTo = '/admin'; protected $guard = 'admin'; public function showLoginForm() {     if (view()->exists('auth.authenticate')) {         return view('auth.authenticate');     }          return view('admin.auth.login');     }      public function showRegistrationForm()     {            return view('admin.auth.register');     }   

it will help you to open another login form for admin

creating a middleware for admin

class RedirectIfNotAdmin {     /**      * Handle an incoming request.      *      * @param  \Illuminate\Http\Request  $request      * @param  \Closure  $next      * @param  string|null  $guard      * @return mixed      */     public function handle($request, Closure $next, $guard = 'admin')     {         if (!Auth::guard($guard)->check()) {             return redirect('/');         }          return $next($request);     } } 

register middleware in kernel.php

 protected $routeMiddleware = [     'admin' => \App\Http\Middleware\RedirectIfNotAdmin::class, ]; 

use this middleware in AdminController e.g.,

namespace App\Http\Controllers;  use Illuminate\Http\Request;  use App\Http\Requests; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Auth;  class AdminController extends Controller {     public function __construct(){         $this->middleware('admin');    }     public function index(){         return view('admin.dashboard');     } } 

That's all needed to make it working and also to get json of authenticated admin use

Auth::guard('admin')->user() 

We can access authenticated user directly using

Auth::user() but if you have two authentication table then you have to use

Auth::guard('guard_name')->user()   

for logout

Auth::guard('guard_name')->user()->logout() 

for authenticated user json

Auth::guard('guard_name')->user()   

Hope this helps.

Answers 4

I just done this in my project for two tables namely users and admin but you can do the same for more than two table.
Let's have a look

How to create our own AuthServiceProvider for authenticating users from multiple tables

I have two table admin and users

first of create basic login/register route, view and controller for user table by using Laravel 5.2 artisan command.

php artisan make:auth

Lets make a admin table as users table.

Controller For Admin Part
app/Http/Controllers/AdminAuth/AuthController
app/Http/Controllers/AdminAuth/PasswordController
(Just copied these files from app/Http/Controllers/Auth/AuthController here)

config/auth.php

//Authenticating guards 'guards' => [     'user' =>[         'driver' => 'session',         'provider' => 'user',     ],     'admin' => [         'driver' => 'session',         'provider' => 'admin',     ], ],    //User Providers 'providers' => [     'user' => [         'driver' => 'eloquent',         'model' => App\User::class,     ],     'admin' => [         'driver' => 'eloquent',         'model' => App\Admin::class,     ] ],    //Resetting Password   'passwords' => [     'clients' => [         'provider' => 'client',         'email' => 'auth.emails.password',         'table' => 'password_resets',         'expire' => 60,     ],     'admins' => [         'provider' => 'admin',         'email' => 'auth.emails.password',         'table' => 'password_resets',         'expire' => 60,     ], ],   

route.php

Route::group(['middleware' => ['web']], function () {     //Login Routes...     Route::get('/admin/login','AdminAuth\AuthController@loginPage');     Route::post('/admin/login','AdminAuth\AuthController@login');     Route::get('/admin/logout','AdminAuth\AuthController@logout');      // Registration Routes...     Route::get('admin/register', 'AdminAuth\AuthController@registrationPage');     Route::post('admin/register', 'AdminAuth\AuthController@register');      Route::get('/admin', 'AdminController@index');  });   

AdminAuth/AuthController.php

Add two methods and specify $redirectTo and $guard

protected $redirectTo = '/admin'; protected $guard = 'admin'; public function loginPage() {     if (view()->exists('auth.authenticate')) {         return view('auth.authenticate');     }      return view('admin.auth.login'); } public function registrationPage() {     return view('admin.auth.register'); }   

it will help you to open another login form for admin

creating a middleware for admin

class RedirectIfNotAdmin { /**  * Handle an incoming request.  *  * @param  \Illuminate\Http\Request  $request  * @param  \Closure  $next  * @param  string|null  $guard  * @return mixed  */ public function handle($request, Closure $next, $guard = 'admin') {     if (!Auth::guard($guard)->check()) {         return redirect('/');     }      return $next($request); } 

}

register middleware in kernel.php

 protected $routeMiddleware = [     'admin' => \App\Http\Middleware\RedirectIfNotAdmin::class, ]; 

use this middleware in AdminController e.g.,

namespace App\Http\Controllers;  use Illuminate\Http\Request;  use App\Http\Requests; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Auth;  class AdminController extends Controller {     public function __construct(){         $this->middleware('admin');    } public function index(){         return view('admin.dashboard');     } } 

Authentication
We can access authenticated user directly using
Auth::user() but if you have two authentication table then you have to use

Auth::guard('guard_name')->user()   

Like
Auth::guard('admin')->user()

And also for reference check this https://laracasts.com/discuss/channels/laravel/52-auth-multiple-tables?page=1

Answers 5

First create Admin Authenticatable in Illuminate\Foundation\Auth like

    <?php  namespace Illuminate\Foundation\Auth; use Illuminate\Auth\Authenticatable; use Illuminate\Database\Eloquent\Model; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Foundation\Auth\Access\Authorizable; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;      class Admin extends Model implements         AuthenticatableContract,         AuthorizableContract,         CanResetPasswordContract     {         use Authenticatable, Authorizable, CanResetPassword;     } 

Then create Admin Model by extending Authenticatable Admin Model :-

  <?php namespace App; use Illuminate\Foundation\Auth\Admin as Authenticatable;  class Admin extends Authenticatable {     /**      * The attributes that are mass assignable.      *      * @var array      */     protected $fillable = [         'name', 'email', 'password',     ];      /**      * The attributes that should be hidden for arrays.      *      * @var array      */     protected $hidden = [         'password', 'remember_token',     ]; } 

After that you need to modify config/auth.php like below Add in providers array

'admins' => [             'driver' => 'eloquent',             'model' => App\Admin::class,         ],  

and Add in guards array.

 'user' => [             'driver' => 'session',             'provider' => 'users',         ],  'admin' => [             'driver' => 'session',             'provider' => 'admins',         ], 

Now to authenticate from user table

 if (Auth::guard('user')->attempt(['email' => $email, 'password' => $password])) {         $details = Auth::guard('user')->user();         $user = $details['original'];         return $user;     } else {         return 'auth fail';     } 

Uthenticate from Admin table

 if (Auth::guard('admin')->attempt(['email' => $email, 'password' => $password])) {         $details = Auth::guard('admin')->user();         $user = $details['original'];         return $user;     } else {         return 'auth fail';     } 

Answers 6

Create a model for managers table and admins table. This model should extend Illuminate\Foundation\Auth\User

In config/auth.php,

Add to the providers array:

'managers' => [     'driver' => 'eloquent',     'model' => App\Manager::class,  ], 

Add to the guards array:

'web_manager' => [     'driver' => 'session',     'provider' => 'managers',  ], 

Then. in LoginController (create one for manager using php artisan make:auth) use the trait Illuminate\Foundation\Auth\AuthenticatesUsers and override guard and redirect properties.

protected $redirectTo = 'redirect_path_after_manager_login';  protected function guard() {   return Auth::guard('web_manager'); } 

The manager model is authenticated and you can get the auuthenticated manager's object Auth::guard('web_manager')->user();

Read More

Wednesday, September 13, 2017

Using AWS Cognito can I resolve the authenticated IdentityId given a disabled unauthenticated IdentityId?

Leave a Comment

I have a JavaScript web application that supports Cognito unauthenticated identities. I'm trying to figure out how to identify the linked authenticated IdentityId for a DISABLED unauthenticated IdentityId.

First unauthenticated users are issued an IdentityId via AWS.config.credentials.get. Internally CognitoIdentityCredentials is using getId to generate a new unauthenticated IdentityId.

let unathenticatedIdentityId;  const AWS = require('aws-sdk'); AWS.config.region = region; AWS.config.credentials = new AWS.CognitoIdentityCredentials({     IdentityPoolId }); AWS.config.credentials.get(err => {     unathenticatedIdentityId = AWS.config.credentials.identityId; }); 

Then our user authenticates to a Cognito User Pool via amazon-cognito-identity-js and the unauthenticated IdentityId changes to the authenticated IdentityId associated with their Cognito Login. The unauthenticated IdentityId is automatically marked DISABLED and is linked internally to the authenticated IdentityId.

let authenticatedIdentityId;  const { CognitoUserPool, CognitoUser, AuthenticationDetails } = require('amazon-cognito-identity-js'); const Pool = new CognitoUserPool({     UserPoolId,     ClientId, }); const authDetails = new AuthenticationDetails({     Username,     Password, }); const user = new CognitoUser({     Pool,     Username, }); user.authenticateUser(authDetails, {     onSuccess: (session) => {         AWS.config.credentials.params.Logins = {             [PoolProviderName]: session.idToken.jwtToken,         };         AWS.config.credentials.expired = true;          AWS.config.credentials.refresh(err => {             authenticatedIdentityId = AWS.config.credentials.identityId;         });     }, }); 

I have the value for unathenticatedIdentityId and authenticatedIdentityId but I do not see a way in the AWS Cognito API's to resolve that the DISABLED unauthenticatedIdentityId has been linked to the authenticatedIdentityId. Conversely I do not see a way to identify what IdentityIds have been linked to the authenticatedIdentityId. The describeIdentity API will tell me that unauthenticatedIdentityId is DISABLED and that it has no Logins, but it does not point to the linked authenticatedIdentityId.

How can I, with only the value of the linked/DISABLED unauthenticatedIdentityId, resolve the value authenticatedIdentityId?

1 Answers

Answers 1

I have an app that uses AWS Cognito to obtain an identity id and then possibly authenticate it. The situation is a client uses the app first as unauthenticated (guest) and then logs in using Facebook, making him/herself as authenticated, and AWS preserves the given identity ID for the authenticated user, because he is a new user. Now, the problem comes, when you log out of the app and someone else wants to use this app as unauthenticated or even authenticated. Cognito will error out saying that the access to the identity ID is forbidden, because it has already been linked to the previous user's Facebook account.

The Cognito mobile SDKs have a way built in to handle this. They cache the identity id when using it, which is causing the issue you are seeing. When you log out, you'll want to clear that cache. I'm not sure which SDK you're using, but in iOS it's AWSCognitoIdentityProvider.clear() and CognitoCachingCredentialsProvider.clear() in Android. Similarly, if you're using Cognito Sync, there's a method in that client that will wipe the cached id and sync data.

Also have a look at https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication/

Hope you are also following https://aws.amazon.com/blogs/mobile/using-the-amazon-cognito-credentials-provider/

Read More