I'm trying to implement SAML authentication against Azure AD in my Laravel application using aacotroneo/laravel-saml2 package.
I configured the IDP settings and the microsoft login page appears correctly as it should be.
The problem is that I'm not able to take user informations from Azure.
I followed the instructions found in the answer of this question Azure Active Directory SSO with Laravel
I changed the code inside the file app/Providers/SAML2ServiceProvider.php adding these lines:
public function boot()
{
Event::listen('Aacotroneo\Saml2\Events\Saml2LogoutEvent', function ($event) {
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
unset($_SESSION["id"]);
session_destroy();
});
Event::listen('Aacotroneo\Saml2\Events\Saml2LoginEvent', function (Saml2LoginEvent $event) {
$messageId = $event->getSaml2Auth()->getLastMessageId();
// Add your own code preventing reuse of a $messageId to stop replay attacks
if (session_status() == PHP_SESSION_ACTIVE) {
session_start();
}
$user = $event->getSaml2User();
Log::info("COOKIE_SAML ACTIVATED");
$_COOKIE["COOKIE_SAML"] = 1;
$userData = [
'id' => $user->getUserId(),
'attributes' => $user->getAttributes(),
'assertion' => $user->getRawSamlAssertion()
];
Log::info(json_encode($userData));
$inputs = [
'sso_user_id' => self::getValue($user->getUserId()),
// 'username' => $user->getAttribute('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'),
'email' => self::getValue($user->getAttribute('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name')),
'first_name' => self::getValue($user->getAttribute('http://schemas.microsoft.com/identity/claims/displayname')),
'last_name' => self::getValue($user->getAttribute('http://schemas.microsoft.com/identity/claims/displayname')),
];
$user = UserAdecco::where('sso_user_id', $inputs['sso_user_id'])->where('email', $inputs['email'])->first();
if (!$user) {
$res = UserAdecco::store($inputs);
if ($res['status'] == 'success') {
$user = $res['data'];
$_SESSION["id"] = $user->id;
// Auth::guard('web')->login($user);
} else {
Log::info('SAML USER Error ' . $res['messages']);
}
} else {
$_SESSION["id"] = $user->id;
// Auth::guard('web')->login($user);
}
});
}
But it seems that this code is not executed at all. The result is that when I login nothing happens and the user is not logged inside the Laravel application.
What am I missing?
I found the problem, the service provider needs to be registered inside config/app.php to work.
Related
I have a Laravel 4.2 app that I have successfully implemented Authorization Code using oauth2-server-php. However, I can't seem to get User Credential grants working.
Here's my code setting up the oauth server:
App::singleton(
'oauth2',
function () {
$host = Config::get('database.connections.mongodb.host');
$hosts = is_array($host) ? $host : [$host];
$dbName = Config::get('database.connections.mongodb.database');
$dbOptions =
empty( Config::get('database.connections.mongodb.options') ) ? [] : Config::get(
'database.connections.mongodb.options'
);
$mongo = new MongoClient('mongodb://' . implode(',', $hosts) . '/' . $dbName, $dbOptions);
$storage = new OAuth2\Storage\Mongo($mongo->{$dbName});
$server = new OAuth2\Server(
$storage, [
'always_issue_new_refresh_token' => true,
'refresh_token_lifetime' => 2419200,
]
);
$userStorage = new \Medusa\Oauth\Storage\MedusaUserCredentials();
$server->addStorage($userStorage, 'users');
$userCredentialGrant = new Oauth2\GrantType\UserCredentials($userStorage);
$server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage));
$server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage));
$server->addGrantType($userCredentialGrant);
$server->addGrantType(new OAuth2\GrantType\RefreshToken($storage));
return $server;
}
);
MedusaUserCredentials has the following code:
namespace Medusa\Oauth\Storage;
use OAuth2\Storage\UserCredentialsInterface;
class MedusaUserCredentials implements UserCredentialsInterface
{
public function checkUserCredentials($username, $password)
{
return Auth::attempt(['email_address' => strtolower($username), 'password' => $password, 'active' => 1]);
}
public function getUserDetails($username)
{
return ['user_id' => $username];
}
}
When I post to the web server to the token route using a raw payload of
grant_type=password&username=<USERNAME>&password=<PASSWORD>
I just get the login page. The token route looks like this
Route::post(
'oauth/token',
function () {
$bridgedRequest = OAuth2\HttpFoundationBridge\Request::createFromRequest(Request::instance());
$bridgedResponse = new OAuth2\HttpFoundationBridge\Response();
$bridgedResponse = App::make('oauth2')->handleTokenRequest($bridgedRequest, $bridgedResponse);
print_r($bridgedResponse); die();
return $bridgedResponse;
}
);
What am I missing?
Thanks!
I found the issue -- I had a namespace issue that I had to resolve. For some reason, my app returned a 200 OK response and the normal login page, so I didn't think to check the logs.
I know, bad dev, no cookie!
PROBLEM: JWTAuth::attempt($credentials) is working in my windows local machine. When user calls /userLogin by providing credentials(username & password), it verifies the credentials and creates a token for the user. But same code: JWTAuth::attempt($credentials) is NOT working when I deploy the project on to Ubuntu Server.
DESCRIPTION:
I am using tymondesigns/jwt-auth for implementing JSON Web Tokens in my Laravel 5.1 project. I have built 2 REST APIs: /userRegister & /userLogin.
Here is code for /userRegister in UserController.php:
public function userRegister(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required',
'username' => 'required',
'password' => 'required',
'country' => 'required',
'zip_code' => 'required',
'date_time' => 'required',
'gender' => 'required',
]);
try
{
if ($validator->fails())
throw new Exception($validator->errors(), 409);
$name = $request->input('name');
$email = $request->input('email');
$username = $request->input('username');
$password = bcrypt($request->input('password'));
$country = $request->input('country');
$zip_code = $request->input('zip_code');
$fb_login = $request->input('fb_login');
$registration_date = $request->input('date_time');
$gender = $request->input('gender');
$user_email = UserProfile::where('email','=',$email)->first();
if($user_email!=null)
{
throw new Exception("User with this email is already registered");
}
$check_username = UserProfile::where('username','=', $username)->first();
if ($check_username != null)
{
throw new Exception("User with this username is already registered. Please use different username");
}
$saveUser = new UserProfile();
$saveUser->name=$name;
$saveUser->email=$email;
$saveUser->username=$username;
$saveUser->password=bcrypt($password);
$saveUser->country=$country;
$saveUser->zipcode=$zip_code;
$saveUser->gender=$gender;
$saveUser->fb_login=$fb_login;
$saveUser->registration_date=$registration_date;
$build_trial_date = new Carbon($registration_date);
$trial_end_date = $build_trial_date->addDays(30);
$saveUser->trial_end_date=$trial_end_date;
$result = $saveUser->save();
if (!$result)
throw new Exception("Error in registration. Please try again.");
$user_id = $saveUser->id;
$loginUser = UserProfile::find($user_id);
$loginUser->update(['logged_in' => 1]);
return ResponseService::buildSuccessResponse("User registered successfully");
}
catch(Exception $e)
{
$data = [
'error' => true,
'result' => [
'status_code' => $e->getCode(),
'message' => $e->getMessage(),
]
];
$result = ResponseService::buildFailureResponse($data);
return $result;
}
}
As you can notice I am using bcrypt() for before saving password.
Now, here is code for /userLogin in UserController:
public function userLogin(Request $request)
{
// grab credentials from the request
$credentials = $request->only('username', 'password');
Log::info("username and password obtained from Request: ".json_encode($credentials));
try
{
if(JWTAuth::attempt($credentials)) // For Logging
{
Log::info("$ token = JWTAuth::attempt $ credentials Result: TRUE");
}else{
Log::info("$ token = JWTAuth::attempt $ credentials Result: FALSE");
}
// attempt to verify the credentials and create a token for the user
if (! $token = JWTAuth::attempt($credentials))
{
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['error' => 'could_not_create_token'], 500);
}
Log::info("Generated token is: ".json_encode(compact('token')));
// all good so return the token
return response()->json(compact('token'));
}
/userRegistration Api is working both in my windows local m/c as well
as in Ubuntu server. Also bcrypt() on password is working in
it.
BUT, /userLogin is working in my windows local m/c but not working in
Ubuntu Server.
Help me solve this silent-dead-hidden error. TIA.
FURTHER DETAILS:
I have also cross-checked jwt.php file both in my windows and ubuntu server. They are having same configuratons. Also I have used php artisan jwt:generate on ubuntu server.
I finally could solve the problem when I went through the code again. Luckily I could noice that! Here is the mistake I did. At some point in time I have added this code bcrypt() like this:
$password = bcrypt($request->input('password'));
But I was already using bcrypt() before saving $password into the database.
$saveUser = new UserProfile();
$saveUser->password=bcrypt($password);
Since it was encrypting twice before saving to database, when I called /userLogin api, JWTAuth::attempt($credentials) was checking for credintials and it was not able to validate. So I removed bcrypt() at one place and now its working fine. [Solved].
I'm writing an app(run on web and Android) for my company's staffs and I want to use Parse.com to store data.
But I'would like to use my company MYSQL database to check if my staffs account and password is correct.
If I have a php file on my server,
for example something like:
<?php
$account=$_POST['account'];
$pw=$_POST['pw'];
if (checkifpwiscorrect($account,$pw)==true) {
//how can the user also log in to Parse
} else {
// account or password wrong
}
?>
How to log in to Parse if account and password is correct?
here is an login function which actually use the restClient class request method.
public function login($username, $password) {
if (!empty($username) || !empty($password)) {
$request = $this->request(array(
'method' => 'GET',
'requestUrl' => 'login',
'data' => array(
'username' => $username,
'password' => $password
)
));
return $request;
} else {
$this->throwError('username and password field are required for the login method');
}
}
I have a registration form in my site,where the users submits their personal details such as name,email id,dob,and mobile number to be stored in my database. Now I am in the idea to include the connect with facebook button,,by using that link,the user can provide their details by logging into their account. those details can be stored in my database. my expectation looks like this image..help me to implement this
First, you need to decide whether you want to use PHP or JavaScript for Facebook's SDK. Then, download the SDK from:
https://developers.facebook.com/docs/facebook-login/login-flow-for-web/v2.2
Here's a "Getting started" guide for PHP:
https://developers.facebook.com/docs/php/gettingstarted/4.0.0
And here's the same kind of guide for JavaScript:
https://developers.facebook.com/docs/javascript
Here's a part of my code for Facebook Login written with PHP. Note that I'm using CodeIgniter as a framwork for my project:
public function registerWithFacebook()
{
try {
// Proceed knowing you have a logged in user who's authenticated
$facebook_user_data = $this->facebook->get_user();
} catch (FacebookApiException $e) {
$user = null;
print_r($e);
return false;
}
// if we don't have the facebook-user array variable, leave the method
if (!$facebook_user_data) {
return false;
}
// If we can't get the email, leave the method
if(!$facebook_user_data['email']) {
return false;
}
// If user is already registered with Facebook, start sessions and redirect user to app home page (exit the method at this point)
if ($this->facebook_model->facebookUserIdExistsAlreadyInDatabase($facebook_user_data)) {
$session = $this->user_model->getUserInfo($facebook_user_data['id']);
$data = array(
'user_id' => $session['user_id'],
'name' => $session['name'],
'email' => $session['email'],
'profilepic' => $session['profilepic'],
'loggedin' => true,
);
$this->session->set_userdata($data);
redirect(base_url().'home');
exit();
}
// Generate password for new user since you can't get the password from Facebook (obviously)
$generated_password = random_string('alnum', 8);
$data = [
'email' => $facebook_user_data['email'],
'name' => $facebook_user_data['name'],
'password' => $this->phpass->hash($generated_password),
'profilepic' => 'https://graph.facebook.com/'.$facebook_user_data['id'].'/picture?width=160&height=160',
'user_facebook_id' => $facebook_user_data['id'],
];
// Insert data to your database
$new_user = $this->facebook_model->add_facebook_user($data);
// If new user's data was saved successfully to database, start sessions and redirect user
if($new_user) {
$session = $this->user_model->getUserInfo($facebook_user_data['id']);
$data = array(
'user_id' => $session['user_id'],
'name' => $session['name'],
'email' => $session['email'],
'profilepic' => 'https://graph.facebook.com/'.$facebook_user_data['id'].'/picture?width=160&height=160',
'loggedin' => true,
);
$this->session->set_userdata($data);
redirect(base_url().'home');
}
}
I am using Artdarek's lib for Laravel but I have a problem.
when users try to login with Twitter they are redirected to Twitter authenticate page and asked for permission.
But if they authorize that app Twitter redirects them to page
"Redirecting you back to the application. This may take a few moments."
and then redirect back to authenticate page on Twitter.
authenticate?oauth_token=UNbRevLchuLCYxsDlgqHODQMmA4osBHoOKbzPLdkCs
Here is my config app/config/packages/artdarek/oauth-4-laravel/config.php
'storage' => 'Session',
'consumers' => array(
'Twitter' => array(
'client_id' => 'xxxxxxAPI key',
'client_secret' => 'xxxxxxAPI secret'
)
)
and here is my login function
public function twiiter() {
$code = Input::get('code');
$oauth_verifier = Input::get( 'oauth_verifier' );
$twitterService = OAuth::consumer('Twitter');
if(!empty($code)) {
$token = $twitterService->getStorage()->retrieveAccessToken('Twitter');
$twitterService->requestAccessToken( $code, $oauth_verifier, $token->getRequestTokenSecret() );
$result = json_decode( $twitterService->request( 'account/verify_credentials.json') );
$user = User::where( [ 'twitter_id' => $result->id ] )->first();
if ( $user ) {
$user->twitter_id = $result->id;
$user->save();
Auth::login($user);
return Redirect::to('/');
} else {
}
} else {
$token = $twitterService->requestRequestToken();
$url = $twitterService->getAuthorizationUri(['oauth_token' => $token->getRequestToken()]);
return Redirect::to((string)$url);
}
}
How to fix this problem? I checked in apps.twitter and my app can Sign in with Twitter, where did I made mistake?
I believe Twitter doesn't use the code variable, rather just the oauth_token which you see in the redirection url.
Here's the official example for Twitter, notice this line specifically:
if (!empty($_GET['oauth_token'])) {
So the reason you keep getting redirected is because no code querystring key is ever set, and therefore it keeps retrieving an access token etc.