OpenID Directed Identity/Identifier Selection in PHP - php

I'm trying to implement an OpenID server in PHP that supports identifier selection (some call this directed identity, which is actually a more specific case of identifier selection). That is, a user can enter a generic URI as their OpenID identifier, log in, and choose what identifier to return to the OpenID consumer.
For example, if a user enters mysite.com as their indentifier, after they log in they would be prompted to return one of two identifiers to the OpenID consumer (perhaps mysite.com/myusername or mysite.com/anon-ad83f38c98b98).
The advantage of this system is that you have the option to either use a single identifier among many sites, or use unique identifiers for individual sites.
Anyway—I haven't been able to find a good tutorial on how to implement this portion of the OpenID spec in PHP. In fact, most searches led me to unanswered questions on forums or even on stack overflow. Does anyone know of a PHP library that can handle identifier selection or directed identity? If so, are there any tutorials out there explaining how to set it up? I've been playing with a few libraries that don't mention it one way or the other, but I haven't been able to get it working yet.
Any help is greatly appreciated.

The documentation is useless. Have you had a look at the Janrain libraries? They have a consumer which I have successfully implemented and also server code which I presume is implementable. Have a look at the Yadis\XRIRes and Yadis\XRI files, you may have to reverse engineer their code - that's what I had to do to figure out the consumer. I'm currently looking into implementing a server but can't find anything worthwhile yet.
http://openidenabled.com/files/php-openid/docs/2.1.3/OpenID/Auth_Yadis_Yadis.html

php-openid v2 is certainly capable. And really, how you interact with the library changes rather little when you add identifier selection. When you get your Auth_OpenID_ChecKIDRequest, you can check its idSelect method to see if it's a case for identifier selection. Then pass the selected identity to Auth_OpenID_ChecKIDRequest.answer().
The only other bit is to make sure that you advertise what the spec terms an "OP Identifier Element" on mysite.com/. If you're serving XRDS pages for your user identifiers already, this works the same way, just with a different Type URL. If you're not (you just have HTML-based discovery with link elements), you might want to look at myopenid's HTTP headers for an example.

Related

Is it secure to send a php value in a link

I have a dynamic page where it should take data from a db. So the approach I thought of was to create the dynamic page with this php code at the top
<?php $pid = $_GET["pid"]; ?>
Then later in the file it connects to the database and shows the correct content according to the page ID ($pid). So on the home page, I want to add the links to display the correct pages. For example, the data for the "Advertise" page is saved in the database in the row where the pid is 100. So I added the link to the "Advertise" page on the homepage like this:
Advertise</li>
So my question is, anyone can see the value that's send on the link and play around by changing the pid. Is there an easy way to mask this value, or a safer method to send the value to the page.php?
The general concept you're looking for is Access Control. You have a resource (in this case, a page and its content), and you want to control who can access it (users, groups, etc), and probably how they can access it as well (for example, read-only, read-and-write, write-but-only-on-the-first-Monday-of-the-month, etc).
Defining the problem
The first thing you need to decide is which resources you need access control for, and which you don't. It sounds to me like some of these pages are supposed to be "public access" (thus they are listed on some kind of index page), while others are supposed to be restricted in some way.
Secondly, you need to come up with an access policy - this can be informally described for a small project, but larger projects usually have some structured system for defining this policy. For each resource, your policy should answer questions like:
Do you have some kind of user account system, and you only want account holders (or certain types of account holders) to access it? Or, are you going to send links to email addresses, and want to limit access to just those people who have the link?
What kind of access should each user have? Read-only? Should they be able to change the content as well (if your system supports that)?
Are there any other types of restrictions on a users' access? Group membership? Do they need to pay before they get access? Are they only allowed access at specific times?
Implementing your policy
Once you've answered these questions, you can start to think about implementation. As it stands, I think you are mixing up access control with identification. Your pid identifies a page (page 100, for example), but it doesn't do anything to limit access. If your pages are identified with a predictable numbering scheme, anyone can easily modify the number in the request (this is true for both GET requests, such as when you type a URL into an address bar, and POST requests, such as when you submit a form).
To securely control access there needs to be a key, usually a string that is very difficult to guess, which is required before access is granted. In very simple systems, it is perfectly fine for this key to be directly inserted in the URL, provided you can still keep the key secret from unauthorized users. This is exactly how Google Drive's "get a link to share" feature works. More complex systems will use either a server-side session or an API key to control access - but in the end, it's still a secret, difficult-to-guess string that the client (user or user's browser) sends to the server along with their request for the resource.
You can think of identification like your street address, which uniquely identifies your house but is not, and is not meant to be, secret. Access control is the key to your house. Only you and the people you've given a key to can actually get inside your house. If your lock is high quality, it will be difficult to pick the lock.
Bringing it together
Writing code is easy, designing software is hard. Before you can determine the solution best for you, you need to think ahead about the ramifications of what you decide. For example, do you anticipate needing to "change the keys" to these pages in the future? If so, you'll have to give your authorized users (the ones that are still supposed to have access) the new key when that happens. A user-account system decouples page access control from page identification, so you can remove one user's access without affecting everyone else.
On the other hand, you also need to think about the nature of your audience. Maybe your users don't want to have to make accounts? This is something that is going to be very specific to your audience.
I get the sense that you're still fairly new to web development, and that you're learning on your own. The hardest part of learning on one's own is "learning what to learn" - Stack Overflow is too specific, and textbooks are too general. So, I'm going to leave you with a short glossary of concepts that seem most relevant to your current problem:
Access control. This is the name of the general problem that you're trying to solve with this question.
Secrecy vs obscurity. When it comes to security, secrecy == good, obscurity == bad.
Web content management system. You've probably heard of Wordpress, but there are tons of others. I'm not sure what your system is supposed to do, but a content management system might solve these problems for you.
Reinventing the wheel. Good in the classroom, bad in the real world.
How does HTTP work. Short but to the point. A lot of questions I see on SO stem from a fundamental misunderstanding of how websites actually work. A website isn't so much a single piece of software, as a conversation between two players - the client (e.g. the user and their browser), and the server. The client can only say something to the server via a request, and the server can only say something to the client via a response. Usually, this conversation consists of the client asking for some resource (an HTML web page, a Javascript file, etc), to which the server responds. The server can either say "here you go, I got it for you", or respond with some kind of error ("I can't find it", "you're not allowed to see that", "I'm too busy right now", "I'm not working properly right now", etc).
PHP The Right Way. Something I wish I had found when I first started learning web development and PHP, not seven years later ;-)
It is always safer to $_POST when you can, but if you have to use something in the query string, it is safer to use a hash or GUID rather than something that is so obviously an auto-incremental value. It makes it harder to guess what the IDs would be. There are other ways values can be past between pages ($_SESSIONs, cookies etc), but it is really about what you want to achieve.
Sending it to php is not an issue, should be fine.
What php does with it afterwards... that's how you secure.
First thing I'd do is make sure it's an integer.
$pid=(is_int($_GET['pid']))? $_GET['pid'] : 1; //1 is the default pid, change this to whatever you want.
Now that you know you're dealing with an integer, use $pid after that and you should be good to go.

Tips for reliable OpenID with your own domain

I'm trying to build a personal OpenID-based online identity using my domain name as identifier. I want to be able to accomplish all this:
Make http://alvaro.es/ my identifier.
Be able to switch providers transparently.
Log into any third-party site that accepts OpenID.
Be able to provide personal details (e-mail, time zone, avatar...) and get prompted whether to send them or not to sites that request them.
Accept OpenID in my own (PHP-powered) sites without the need of purchasing SSL hosting.
I've read the usual doc and I've been evaluating several OpenID providers (Google, Yahoo, myOpenID... and even running my own server). The fact is that I've been using OpenID for a while and:
Providers offer very scarce documentation or none at all.
No matter what provider I choose, there are always sites where log-in fails (typically without an error message).
I have little control (or none at all) on the identifier returned by the provider.
I still can't understand how all this really works.
I'm looking for general advice but I understand that can be subjective so I'll make a few specific questions.
So far, I'm trying out myOpenId as provider and LightOpenID as consumer. My questions are:
My URL provides an HTTP header:
X-XRDS-Location: http://kalvaro.myopenid.com/?xrds=1
... and the following HTML tags:
<link rel="openid.server openid2.provider" href="http://www.myopenid.com/server">
<link rel="openid.delegate openid2.local_id" href="http://kalvaro.myopenid.com">
Is it correct? Is it enough?
myOpenID provides Your Domains, a feature to register your own domain name but I haven't dared to test it (it needs changes to the DNS) and the configuration form suggests I have to choose between http://openid.alvaro.es/username and http://username.alvaro.es/ as identifier (not http://alvaro.es/). However, Stackoverflow still reports alvaro.es as my identifier without this feature. Do I need to use it?
When implementing LightOpenID, I match the local user against $openid->identity (where $openid is the instance of the LightOpenID object). This attribute appears to be the URL supplied by the user. Is it correct?
Are there more adequate providers or consumer libraries than the ones I chose?
It is correct. It is more than enough. While providing an X-XRDS-Location is a good thing, as it sepeeds up the discovery process, it isn't sctrictly necessary.
As far as I understand it, "Your Domains" is useful when you want to have multiple accounts in your domain. Anyway, you don't need to use it at all.
It is correct. The url is also called a Claimed Identifier, i.e. what the user claims to be.
As the author of LightOpenID, my answer is obvious and possibly biased -- I've created it, because I couldn't find a good, existing library.
Other things you might want to know:
Delegation won't work with Google, and any other provider who uses select_identifier (i.e. each account has the same url, and then the provider asks you for your login).
Your delegation, as shown in 1., will let you switch providers transparently and log in to any site that supports OpenID, just as you want.
As for the personal details, it depends completely on the provider, whether it sends them or not, what kind of personal information it supports, etc.. For example, Google doesn't let you choose what to send, only whether to send something (and everything the website claims to require) at all.
Some implementations are buggy and indeed fail. Try logging in for a second time, it works sometimes.
The identifier returned by your provider shouldn't matter if you use delegation. The website you're logging into should use your claimed identifier.
As for how the openid works, see some answers to that question on SO.

Advise needed on outsourcing the recording of unique views

I have an online image sharing platform based on PHP5 + CodeIgniter. I would like the application to show to the user the number of unique views per image. Users can access image pages anonymous or signed in.
Although I know how to implement such a thing myself, I prefer to "outsource" the recording of unique pageviews, for reasons of performance and complexity (determining unique pageviews). My requirements for such a service:
Must record unique page views
Must have an API that allows me to get the #pageviews for one specific page programmatically. This goes beyond just displaying it, I may need to do calculations with this number
Semi-realtime information is good enough. Reasonable delays are acceptable
Low cost or free
My question is: Do you know of such a service and which one would you recommend or have experience with? In your answer, please assume an "outsourced" scenario, not DIY.
Piwik is a self-hosted, Open Source tool that sports an API. I have no experience with it yet, but looking at the API docs, it might be able to do what you need (no guarantees though).

How to distinguish/identify users with OpenID without requesting SReg fields?

I've been toying with the JanRain OpenID PHP Library, mostly following along with a tutorial I found on ZendZone.
How does one distinguish between users - especially Google users, who all end up using the same OpenID URL, https://www.google.com/accounts/o8/id ?
Basically, I'm at the point where I can detect that they have an OpenID account... that they've successfully authenticated... but my app still doesn't know who they are; only that they authenticated.
To distinguish users, the tutorial uses a "Simple Registration request" to request the user's email of the OpenID provider - and then use email address to see if this is a returning user.
It wasn't working for me, and apparently won't work with some providers so I was excited when I stumbled upon a function getDisplayIdentifier.
require_once "Auth/OpenID/Consumer.php";
require_once "Auth/OpenID/FileStore.php";
// create file storage area for OpenID data
$store = new Auth_OpenID_FileStore('/wtv');
$consumer = new Auth_OpenID_Consumer($store);
$oid_response = $consumer->complete("http://example.com/oir_return");
if ($oid_response->status == Auth_OpenID_SUCCESS) {
$hopefullyUniqueUserID = $oid_response->getDisplayIdentifier(); // I assumed this would be a relatively permanent way to identify the user...
// I was wrong.
}
Unfortunately, after a couple of hours the value returned by getDisplayIdentifier changes.
Skimming the code, I think it's $oid_response->identity_url that you want. For me (albeit in DotNetOpenAuth not php-openid) that comes back as
https://www.google.com/accounts/o8/id?id=AItOawmqjknrgk6f9cNdPIVxW43GewJPa1ZW4GE
from Google, where the ID part is reproducible and hopefully unique to me. However I haven't left it a few hours to see if this changes, so apologies if this is what you already had from getDisplayIdentifier - but skimming the source it looks like it'd just use the first part, but then I'm no PHP expert.
The problem was that Google's OpenIDs are Unique Per-Domain; I had been absent mindedly alternating between http://www.mysite.com and http://mysite.com, which caused the OpenID identity url to change!
Why not simply use the OpenID URL to identify users? Consider it unique like an email address.
According to the last paragraph below, you should definitely use the identity_url attribute of the response object (granted, this is in reference to the Python library, but the implementations are very similar):
The display identifier is related to the Claimed Identifier, but the
two are not always identical. The display identifier is something the
user should recognize as what they entered, whereas the response's
claimed identifier (in the L{identity_url} attribute) may have extra
information for better persistence.
URLs will be stripped of their fragments for display. XRIs will
display the human-readable identifier (i-name) instead of the
persistent identifier (i-number).
Use the display identifier in your user interface. Use
L{identity_url} for querying your database or authorization server.
From the python-openid docs.

OpenID -- getting user information?

I am wondering if it is possible to request more information besides email from Google and get the name of the user also?
Am using JanRain OpenID PHP script.
Thank you
No, it isn't possible. Google only releases the user's email address. Their server is set up to never give out any more information than that:
See their OpenID page for developers to learn more:
http://code.google.com/apis/accounts/docs/OpenID.html
Search for OpenID Attribute Exchange -- that's what you want.
basic overview
formal specification
We haven't looked at it in a while (6 months?) but it was quite rough when we did. Hopefully things have improved since then.
More resources:
http://www.google.com/search?q=openid+attribute+exchange
I normally read the manual only when truly defeated. For 3 days, I have tried different ways to fetch user attributes from those two giant OpenID providers, but only managed to fetch the "email" attribute from Google and absolutely nothing from Yahoo. And then I had to read the dreaded manual, even those vague OpenID specifications.
So why implement a standard and not fully support it? Why pretend that there is any viability to OpenID if the big parties will not cooperate with the smaller parties when it comes to information exchange.
I guess the basic sign up and sign in process wins after all... Who really needs to know about XRIs and URLs anyway?
You're not supposed to rely on any user information anyway. See if it's part of the OP's reply, and if it isn't, provide the user with a form where he can complete the required fields.

Categories