I have a third party application which does the authentication and wants to log the user into a locally installed vBulletin instance at the same time. The only way to log in is via this third party app. This is what I have where $vbpath is the path to the vBulletin installation and $username is the name of the user to log in:
require_once($vbpath . '/includes/vb5/autoloader.php');
\vB5_Autoloader::register($vbpath);
\vB5_Frontend_Application::init('config.php');
\vB::getDbAssertor()->delete('session', array('sessionhash' => \vB::getCurrentSession()->get('dbsessionhash')));
$username = \vB_String::htmlSpecialCharsUni($username);
$userinfo = \vB::getDbAssertor()->getRow('user', array('username' => $username));
$auth = array_intersect_key($userinfo, array_flip(['userid', 'lastvisit', 'lastactivity']));
$loginInfo = \vB_User::processNewLogin($auth);
\vB5_Auth::setLoginCookies($loginInfo);
at first sight it seems to work but I am wondering: is there anything else that needs to be done to properly log into vBulletin 5? I bypassed the API because it seemed the API requires the password and quickly becomes a mess if I store it in the third party app -- it needs to be encrypted using the third party password obviously and it's just a huge syncing mess which I didn't really need.
Related
We want to implement a SSO like approach in our program where users will register in a third party program and synchronously register in our program and authenticate the login/logout from the third party. Since we don't have access to the third party's authentication. The 3rd party program is our client's program that wants to use our program's services.
Since packages like miniorage is not free, we need to do this the hard way.
Here is what I have done and will try finish:
Already done code:
Install laravel/passport in our program.
Create an registration API that the client in third party can use to register in our program
With passport, it will return a Bearer token that they need to save in their system (Remove the expi`ration date)
Create a URL that will accept the bearer token that was created during the registration
When the URL is opened, I will be able to use the Auth::user() and get user info.
Trying to accomplish:
$credentials = ([
'email' => 'test#gmail.com',
]);
if (Auth::attempt($credentials)) {
Log::info(Auth::user());
}
From the Auth::user(), get the email address and re-login using the code above
However, when I open another page, the Auth::user() is empty.
My question is:
1 Is this approach okay for a makeshift SSO?
2 Why is the Auth::user() empty on a different url even if I manually login the user?
UPDATE
So I think I will continue with the Laravel Passport as a makeshift SSO on our program. However I want to do a Auth::login() when I pass the token in the header:
Here would be the code:
public function authenticate()
{
$user = Auth::user();
Log::info($user);
. . . . . .
$authuser = User::where('email', '=', $user->email)->first();
$authuser = Auth::login($authuser);
Log::info($authuser);
return $user;
}
The reason why I wish to use Auth::Login here is so that the user is authenticated on all pages. Not just in the first page.
The function authenticate is used when I access the program with the Bearer Token. In the $authuser part, I want to re login the user with just the email. Reason why only email is because of the logic before this. Yes we already consider this one. However when I use the Auth::login($authuser);, it returns Method Illuminate\Auth\RequestGuard::login does not exist error message.
Possible data that you wish to see:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
],
api => driver was originally token before the laravel passport was implemented
Is this approach okay for a makeshift SSO?
It might work with Passport, but it's not really the intended use (OAuth2) for it. I found it more confusing than just rolling out a custom solution:
Install JWT auth - https://jwt-auth.readthedocs.io/en/develop/laravel-installation/
Set guard in config/auth.php
I'd look into using a manual JWT auth solution (https://jwt-auth.readthedocs.io/en/develop/laravel-installation/)
2 Why is the Auth::user() empty on a different url even if I manually login the user?
Most likely because the route/controller method is missing an auth middleware that says it's an authenticated.
After trial and errors, I decided to use Laravel Passport and fixed the Auth::login not persisting. For the Auth::login issue, I moved \Illuminate\Session\Middleware\StartSession::class, from $middlewareGroups to $middleware
I'm a newbie to app development. I am building a Windows Phone 8.1 app and have followed the tutorial here: http://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-dotnet-backend-windows-store-dotnet-get-started-users-preview/ to add authentication using Facebook. Everything seems to work fine, except that every now and again it appears to stop bringing back any data from my Azure database. Further investigation revealed that the UserId that is being shown from the code below, changes periodically (although I can't quite work out how often it changes).
// Define a member variable for storing the signed-in user.
private MobileServiceUser user;
...
var provider = "Facebook";
...
// Login with the identity provider.
user = await App.MobileService.LoginAsync(provider);
// Create and store the user credentials.
credential = new PasswordCredential(provider,
user.UserId, user.MobileServiceAuthenticationToken);
vault.Add(credential);
...
message = string.Format("You are now logged in - {0}", user.UserId);
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
This code is identical to the code in the tutorial. The Facebook app settings (on the Facebook developers site) confirm that I am using v2.3 of their API so I should be getting app-scoped UserIds back. I have only ever logged in with one Facebook account, so I would expect the UserId to be the same each time, but they're not. The UserId is prefaced with 'sid:', which someone on the Facebook developers group on Facebook itself says stands for Session ID, which they would expect to change, but if that's the case, I can't work out where to get the actual UserId from that I can then store in my database and do useful things with. I'm sure I must be doing something basic wrong, but I have spent hours Googling this and cannot (unusually) find an answer.
Any help would be greatly appreciated.
Thanks!
So dug deeper. This is how Mobile Apps work (I was thinking from a Mobile Services perspective). The issue here is that the Gateway doesn't provide static SIDs, which is what User.userId provides. The work around to this is listed in the migration doc.
You can only get the Facebook AppId on the server.
ServiceUser user = (ServiceUser) this.User;
FacebookCredentials creds = (await user.GetIdentitiesAsync()).OfType< FacebookCredentials >().FirstOrDefault();
string mobileServicesUserId = creds.Provider + ":" + creds.UserId;
You should note, that this Id is directly connected with your Facebook App registration. If you ever want to migrate your App to a new Facebook App, you'd have to migrate them. You can also use the Facebook AppId to look up the user's global facebook Id via the Facebook Graph API, which you could use between applications. If you don't see yourself using multiple apps, etc., you can use the Facebook AppId just fine.
Hard to tell what's going on to cause you to use a SID instead of the Faceboook token (which like Facebook:10153...).
It may be faster to rip out the code and reimplement the Auth GetStarted. Maybe you missed a step or misconfigured something along the way. If you have the code hosted on github, I can try to take a look.
Another thing you can do is to not trust the user to give you their User id when you save it to a table. On your insert function, you can add it there.
function insert(item, user, request) {
item.id = user.userId;
request.execute();
}
That should, theoretically, be a valid Facebook token. Let me know if that doesn't work; can dig deeper.
I am using the OAuth Facebook controller add-on for ATK4.
It works as expected when authenticating with Facebook from a regular desktop browser.
It works when authenticating using a mobile browser that is telling face book that it's a desktop browser.
It does not work when Facebook detects a mobile browser and redirects to m.facebook.com/dialog/oath.
What's more, is that it works fine for signups from mobile browsers (ie, when Facebook asks the user to give permission to the app).
The login flow stops with an Error 500 at:
https://m.facebook.com/dialog/oauth?redirect_uri={my_url_encoded_landing_page_where_the_OAuth_controller_lives}&scope=email&client_id={fb_app_id}
What the hell is going on here? There isn't some difference between the Facebook mobile service and the regular one that the addon isn't taking care of, or is there?
It must be something I'm doing wrong. In init() on the page that handles the FB, I am doing the following:
function init(){
parent::init();
$f = $this->add("oauth/Controller_OAuth_Facebook", array('sign_method'=>'PLAINTEXT'));
if ($fbtoken = $f->check()) {
$f->setSignatureInfo();
$f->setAuthToken($fbtoken["access_token"], $fbtoken["expires"]);
$s = $this->add("sni/Controller_SNI_Facebook");
$s->setOAuth($f);
// ...
// grab profile from SNI, database lookup, session stuff, etc
// ...
}
}
I've tried all three sign_methods, and tried leaving it alone, but that doesn't make much difference because the user is not making it back to the controller with an access token to use anyway.
I tried creating a new app with Facebook and I get the same issues with a basically vanilla configuration on that. I've only marked and specified the "Website with Facebook Login" site URL integration.
The image below was captured from Chrome after overriding the user agent to a mobile device to trigger the forward to facebook's mobile servers:
Screen shot of request
Facebook closed my bug report with them stating that it's not an issue since no one else is reporting the bug. I am removing the ATK4 tag, as I get the same issue using the example PHP code provided by Facebook on GIT.
Created dedicated example here:
http://demo.ambienttech.lv/d.html?ns=d3
Example is downloadable and includes instructions of setting up facebook app as well. See if that helps.
Try This:
<?php
class page_fb extends Page {
function init(){
parent::init();
$f = $this->add("oauth/Controller_OAuth_Facebook");
$fbtoken = $this->api->recall("fbtoken");
if ($m = $_GET["error_msg"]){
$v=$this->add("View_Error");
$v->add("Text")->setHTML("You can't connect to the application.");
$v->add("Button")->setHTML("Try again")->js("click", $this->js()->univ()->location("fb"));
return;
}
if (!$fbtoken){
if ($fbtoken = $f->check("email")){
$this->api->memorize("fbtoken", $fbtoken);
$this->api->redirect($this->api->url("/index"));
}
} else {
$f->setSignatureInfo();
$f->setAuthToken($fbtoken["access_token"], $fbtoken["expires"]);
$c = $this->add("sni/Controller_SNI_Facebook");
$c->setOAuth($f);
if (!$this->api->recall("fbuserinfo")){
$this->api->memorize("fbuserinfo", $c->getUserProfile());
}
$info = $this->api->recall("fbuserinfo");
$username = $info->username;
$img = $c->customRequest("/" . $username . "/picture?type=large");
$this->api->memorize("userimg", $img);
$this->api->memorize("userinfo", $info);
if (!$this->api->auth->isLoggedIn()){
$this->api->auth->login($info->email);
}
$this->api->redirect($this->api->url("/index"));
}
}
}
I've got the same problem, but using PHP: just using a mobile web browser is not working, giving '500 internal server error'.
I'm just asking myself if exists a parameter for the method getLoginUrl to force return a non-mobile version of the authentication page...
I reported this issue here: https://github.com/atk4/atk4-addons/issues/35
Please stay tuned and if you can, you can always make changes yourself and pull request.
I can't test and fix this because strangely I still don't have smart phone :(
Something changed in FB's mobile OAuth service that is causing the error. I ran a test with my code base on a shorter URL (ie; http://domain.net/fb/ rather than http://development.project.domain.net/fb) and it works fine. I am not entirely sure of what exactly is causing the problem as Facebook refuses to acknowledge the issue as being on their server, but I have a few possible culprits that may be triggering the error on their side, but since they don't care, I don't either, and I am providing my results for anyone else who encounters this bs.
The environment I am developing in uses semi-complex (apparently) naming scheme. The development server has its own hostname under a subdomain. The issue may be caused by the fact that there are multiple components to the host portion of the URL or simply too many characters.
The name servers for the development environment are provided by DynDNS. Facebook's mobile OAuth service may be choking on the idea of a development site being hosted on a non-permanent IP address.
I'm not going to do anymore testing on this because it really is a problem with Facebook, not my code or servers, and it will work in production.
I am building a facebook app with codeigniter. When a user accepts a request and gets redirected to my app I want to store the request_id in a session. At first it gets stored but when the page is reloaded after the user authenticates the app the requested_id stored earlier doesn't exist anymore.
function save_request_id()
{
$this->session->set_userdata('request_id', $request_id);
}
function retrieve_request_id()
{
$data = $this->session->all_userdata();
print_r($data);
exit;
}
You want to only retrieve the request_id:
$this->session->userdata('request_id');
Sounds like the session is being cleared when the user completes the auth cycle. Are you using the FB PHP SDK? If so, I believe it creates its own session to manage the connected user. Check the library you're using, you may need to adjust it to fit your needs - or devise an alternate solution, like redirecting after auth to a view that can process a request_id in the URL.
session library of CodeIgniter has this problem,use native php session + secuirty lib of CodeIgniter to clean XSS .
I know Omniauth is just for authentication and it doesn't really have FB or Twitter tools included.
However, let's say my Rails 3 app uses Omniauth and I now have some users registered in my system.
How can I then post to their wall? Or do I need some other type of authorization system?
Thanks for any pointers.
I found this link which allowed me to post to both Facebook and Twitter. Very good tutorial:
http://blog.assimov.net/post/2358661274/twitter-integration-with-omniauth-and-devise-on-rails-3
I used this guide while setting up my application to connect to twitter:
http://philsturgeon.co.uk/news/2010/11/using-omniauth-to-make-twitteroauth-api-requests
Helped me a ton, hope it does for you the same.
Original post
Posted: Nov 16, 2010
Using the brilliant user system gem Devise and a gem called OmniAuth you can make a Rails application that logs in or registers users via Twitter, Facebook, Gowalla, etc with amazing ease. But once the user is logged in, how do you go about actually interacting with the API on behalf of the account that has just been authorized?
This article starts where RailsCasts leaves off, so if you are not already up and running with Devise and OmniAuth then you might want to watch:
RailsCast #209: Introducing Devise
RailsCast #235: OmniAuth Part 1
RailsCast #236: OmniAuth Part 2
So, assuming we are all about at the point that the third video ends on, we are all ready to go. I'll be using the example of Twitter but really any of the providers using oAuth will use the same approach. Like in the "ye-olden days" when we used the Twitter username and password to authenticate an API request, we now use a Access Token and Token Secret. You can think of these as being basically the same thing as for the purpose of authenticating API requests, to us, they are.
To get the token and secret you need to add some fields to your authentications table:
rails g migration AddTokenToAuthentications token:string secret:string
rake db:migrate
Now the database is ready to save the credentials we can change the authentication code to populate the fields. Assuming you placed the method in user.rb like RailsCast #236 suggested then open user.rb and modify the following line:
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
and replace it with:
authentications.build(
:provider => omniauth['provider'],
:uid => omniauth['uid'],
:token => omniauth['credentials']['token'],
:secret => omniauth['credentials']['secret']
)
Now whenever anybody authenticates their account we can save their credentials which are passed back from the internal hidden magic that is OmniAuth.
The next step is to actually make some requests using these saved credentials, which is described almost perfectly in the Twitter Developer Documentation. You'll want to install the oauth gem (put it in your Gemfile and run bundle install) then you can use the following code to test-dump a list of tweets from the user:
class TwitterController < ApplicationController
def recent_tweets
# Exchange your oauth_token and oauth_token_secret for an AccessToken instance.
def prepare_access_token(oauth_token, oauth_token_secret)
consumer = OAuth::Consumer.new("APIKey", "APISecret"
{ :site => "http://api.twitter.com"
})
# now create the access token object from passed values
token_hash = { :oauth_token => oauth_token,
:oauth_token_secret => oauth_token_secret
}
access_token = OAuth::AccessToken.from_hash(consumer, token_hash )
return access_token
end
auth = current_user.authentications.find(:first, :conditions => { :provider => 'twitter' })
# Exchange our oauth_token and oauth_token secret for the AccessToken instance.
access_token = prepare_access_token(auth['token'], auth['secret'])
# use the access token as an agent to get the home timeline
response = access_token.request(:get, "http://api.twitter.com/1/statuses/user_timeline.json")
render :json => response.body
end
end
By pulling the content from current_user.authentications (im finding the first as in my application they should only have one) I can grab the credentials and have full permissions to get their recent tweets, post new ones, see friends tweets, etc.
Now I can tweak this, get stuff saved, faff with the JSON and take what I need. Working with Facebook or any other oAuth provider will work in an almost identical way, or you can install specific gems to interact with their API's if the direct approach is not as smooth as you'd like.
end of original post