Showing posts with label web. Show all posts
Showing posts with label web. Show all posts

Friday, January 13, 2017

Feeling safer online with Firefox

The latest privacy and security improvements in Firefox

 

[This post originally appeared on Medium]

Firefox is the only browser that answers only to you, our users; so all of us who work on Firefox spend a lot of effort making your browsing experience more private and secure. We update Firefox every 6 weeks, and every new change ships to you as fast as we can make and verify it. For a few releases now, we have been landing bits and pieces of a broader set of privacy and security changes. This post will outline the big picture of all these changes.

Site Identity and Permissions Panel

The main project involved improvements to the way Firefox handles permission requests from sites that want to do things that the web platform doesn't allow by default - like accessing your laptop's camera or GPS sensor. To find out how our existing model fares, we ran it through a number of user studies and gathered feedback from users and web developers alike.

old-prompt.png

What we found was clear: users were having trouble making full use of web permissions. Here are some of the observations:
  • It’s easy by design to dismiss a permission prompt, to prevent websites from nagging you. But it’s not so obvious how to get back to an inadvertently dismissed prompt, which users found confusing.
  • Managing the permissions of an individual site was hard, due to the multitude of presented options.
  • It was cumbersome to grant access to screen sharing. This was because it was difficult to select which area of the screen would be shared and because screen sharing was only permitted on websites included in a manually curated list.
In order for the open web platform to be on par with the capabilities of native, closed platforms, we needed to fix these issues. So we first focused on putting all privacy and security related information in one place. We call it the Site Identity and Permissions Panel, or more affectionately, the Control Center™.

control-center.png

The Site Identity panel appears when you click on the circled “i” icon – “i” for “information” – on the left side of the Awesome Bar. The panel is designed to be the one-stop shop for all security and privacy information specific to the site you’re on. This includes encrypted connections certificate, mixed content warning messages, tracking protection status, as well as non-default permissions. We were happy to see Chrome adopt a similar UI, too.

Elevated Privileges for Non-Default Permissions

By default, web sites need an elevated level of privilege to access your computer hardware like camera, microphone, GPS or other sensors. When a site requests such a permission and the user grants it, the Site Identity panel will display the allowed item along with an "x" button to revert it. In the case of particularly privacy-sensitive permissions, like microphone or camera access, the icon will have a red hue and a gentle animation to draw attention.


When a site has been granted elevated privileges, the "i" icon in the URL bar is badged with a dot that indicates the additional information present in the Site Identity panel. This lets you assess the security properties of your current session with a quick glance at the awesomebar, where the "i" and lock icons are displayed together.



Users who want even more fine-grained control over all available permissions can go to the Permissions tab in the Page Info dialog (right arrow in the Identity panel -> More Information).

Permission Prompt and Dialog

Permission dialogs are now more consistent than before, both in terms of available actions and messaging.

When a site asks for a permission, a permission prompt appears with a message and iconography specific to the type of permission being requested and the available actions. Most of the time, there will only be two: allow or don’t allow access. The default action will stand out in a blue highlight, making the common action easier to perform.


In the few cases of permission prompts with more than two actions, a drop-down menu will appear next to the secondary action button.


Permanently allowing or rejecting a permission for a site is done by checking the always present "Remember this decision" option.



We have received a lot of feedback about how these prompts are easy to dismiss and how users often couldn't figure out how to bring them back. In the new design, permission prompts stay up even when you interact with the page. You can of course ignore it and continue to use the page normally. But thanks to the persistence of the prompt, it’s now easier to associate site misbehavior – webcams that don’t work, locations that won’t display – with an allow/don’t allow button that needs your response.

Furthermore, disallowed permission requests are now displayed as strikethrough icons in the Awesome Bar to hint at the potential cause of site breakage. For example a video conferencing site will probably not be functioning very well if you reject its camera permission request. So the crossed-out camera icon will remain afterwards, next to the "i" icon, to remind you of that fact.


Going to a different tab will hide the prompt (because it’s specific to the site you have open on each tab), but when the prior tab is selected again, the prompt will reappear.


Audio, Video and Screen Sharing Permissions

WebRTC-related permissions have even more new changes.

For starters, screen sharing now doesn't require sites to be added to a separate whitelist. This means that all sites can now use WebRTC screen sharing in Firefox.

Also, screen sharing now includes a preview of the content that will be shared to make it easier to identify the right screen, application or window to share.


In the riskiest of cases, such as sharing the entire screen or sharing the Firefox application, a scary warning message is displayed to ensure you know what you are about to do.

screen-sharing.png

Moreover, when you have granted a video conferencing site access to both your camera and microphone, reverting the permission grant for one permission will also revert it for the other. This will help you avoid accidentally leaking your private data.

Add-on Panel Improvements

While working on these security improvements we fixed some old platform panel bugs that used to affect all kinds of panels, including those created by add-ons. Therefore if you are using an add-on that displays popup panels you should have an improved experience even if the panels are not related to permission prompts.

Error Pages

And finally, error pages also received some new smarts.

The most common cause for secure connection errors turns out to be user systems having the wrong time. Firefox will now detect when your clock seems way off and will suggest in the error message how to fix it.



Another common cause for broken connections is the presence of a captive portal. Firefox will now detect that case and prompt you to log in the captive portal. Even though some operating systems have built-in support for detecting captive portals, if you regularly use social network accounts to log in, the experience with Firefox will be smoother. This change is now in Nightly and Developer Edition versions and should ship soon in the stable release.


Looking back at what we managed to accomplish in the last few months makes me proud to work with this fabulous team of talented and passionate engineers, designers, user researchers, QA engineers, product and project managers. But of course we are far from being done with privacy and security improvements for our users. Stay tuned for more exciting Firefox privacy and security updates in 2017!

[Many thanks to Bram Pitoyo, Nihanth Subramanya, Tanvi Vyas, Peter Dolanjski, Florian Quèze, and Johann Hofmann for reviewing drafts of this post.]

Tuesday, December 30, 2014

Valence roadmap

A few days ago I sent the following note to the Firefox devtools mailing list. The point was to start a discussion about where we want to take Valence (née Firefox Developer Tools Adapter) in 2015. I am reproducing the message below in an effort to broaden the audience, but I would encourage anyone who wants to participate in the discussion to post to the mailing list. However, if that sounds too intimidating (it really shouldn't!), I'm always happy to respond to comments in this blog.


Hey fellow devtoolers!

I know that eggnog and Christmas trees is all that everyone is thinking about right now, but I'd like to take a minute before we all indulge in our holiday festivities, to talk about Valence. And 2015.

2015 will be the year when Valence becomes something more than a promising experiment. It is the year that will (hopefully) see a version 1.0 that has feature-parity with Firefox, for features where the Safari/Chrome debugging protocol aligns well with the Firefox RDP. This is a proposed roadmap of how we'll get there from where we are now.

There are two main themes in this roadmap: do more and do better, and I think we should address them in reverse order. Do-things-better contains what I think we need for cutting a 1.0 release:

Improve existing features (do better)
  • Get the bundled ios_webkit_debug_proxy working on Windows & Linux
  • Implement support for the network panel
  • Handle format specifiers in console.log and friends (%s, %c, etc.)
  • Display inferred names for functions
  • Evaluate expressions in the selected frame when execution is paused
  • Support source-mapped CSS
  • Break on DOM events
  • Fix some longstring-related bugs that we currently work around by using plain strings
  • Fix every XXX and TODO comment in the code
  • Implement every todoMethod in the actors

Most of these tasks have a well understood scope, so it is just a "small" matter of time and available resources. However, another angle on the do-better theme is not to just fix known problems, but also to make them stay fixed and provide a reliable experience to the user. These tasks belong in that category and should probably be done in parallel with the above:

Improve reliability (do better for realz)
  • Deploy some testing infrastructure (probably based on ted's work)
  • Port existing Firefox devtools tests and/or write new ones
  • Fix stability bugs in Valence

I believe the above lists should be enough for a v1.0, but there are many more things we could do to provide value to our users. Here are some obvious features we could add for a v2.0:

Expand our feature set (do more)
  • Support for the performance panel (profiler and timeline)
  • Support for the storage panel
  • Support for the canvas debugger
  • Support for debugging embedded web views on iOS and Android, which would let us become a sort of unofficial development environment for Cordova/PhoneGap
  • Support Firefox Developer Tools in the pipeline (memory profiler, worker debugger)

Not all of these tasks have been scoped or had a feasibility assessment, but there are some indications that we should be able to pull them off with some effort. These features would make the value proposition of Valence and (Firefox Developer Edition by extension) really enticing for many more developers.

But when you have all this, why stop there? The adaptability of Firefox Developer Tools that Valence affords can take us to a whole new level of debugging functionality that developers have always dreamed of:

Full-stack debugging (do way more)
  • Support debugging server-side node.js applications, with console, scratchpad, debugger and profiler
    • (Adding async stack support in Firefox Developer Tools would let us combine server- and client-side stack traces for debugging ecstasy)
  • Research the framework ecosystems of languages that compile to JS and can run on node.js and assess the feasibility of supporting them directly via source maps
  • Implement adapters for JDWP (to debug Java) and Xdebug (to debug PHP)

Only some preliminary research has gone into these tasks, so their feasibility and effort required is still TBD. Most of the above are further out from a priority standpoint and some may well be in the pie-in-the-sky domain, but I think we should at least investigate node.js debugging in 2015. It would be an exciting engineering accomplishment and could provide a concrete value proposition for Valence and Firefox Developer Edition.

Prioritized shortlist
Given all of the above, and taking difficulty and usefulness into account, I think a reasonable, prioritized, shortlist of Valence tasks for 2015 would be the following:

  1. Get the bundled ios_webkit_debug_proxy working on Windows & Linux
  2. Display inferred names for functions
  3. Implement support for the network panel
  4. Fix stability bugs in Valence
  5. Deploy some testing infrastructure
  6. Port existing Firefox devtools tests and/or write new ones
  7. Support debugging server-side node.js applications
  8. Support for debugging embedded web views on iOS and Android
  9. Handle format specifiers in console.log and friends (%s, %c, etc.)
  10. Evaluate expressions in the selected frame when execution is paused
  11. Support source-mapped CSS
  12. Break on DOM events

Of course, depending on broader organizational priorities, this list may be too short or not much of a shortlist, for an entire year. Not to mention that planning that far ahead is usually futile and an exercise in frustration. Still, this should hopefully provide a useful base for a discussion about what we want Valence to be and how we want to go about it.

Any and all feedback is welcome (before or while you enjoy your eggnog)!

Cheers,
Panos

Tuesday, November 6, 2012

JavaScript debugging updates

There have been a lot of interesting developments in the JavaScript debugging front since my last update, so let me give you a brief overview of the most important changes.

Let's begin with the eagerly awaited Firefox OS. Starting the debugger in Firefox OS has gotten way easier. There is a toggle in the settings app that will set or reset the devtools.debugger.remote-enabled pref, so that you don't have to mess with files and adb at all. At least for production builds that have marionette disabled by default. Developer builds will have to keep disabling marionette for a bit longer. You can find the Remote Debugging toggle in Settings -> Device Information -> More Information -> Developer. Note that you will have to reboot the device (or restart the b2g process) for the change to have effect. Also, as you can see in the screenshot, it's a good idea to disable out-of-process support while debugging, at least until the debugger can support it.

Firefox OS settings
Firefox OS settings
While we are on the subject of debugging JavaScript on mobile, I shouldn't neglect to mention that Mihai Sucan has landed web console support for Firefox OS and Firefox for Android. There are still a few rough edges, particularly in the case of Firefox OS, but now you can connect your desktop Firefox to your mobile device and see the errors and logged messages, as well as evaluate JS code in the context of the mobile page.

Speaking of desktop Firefox, the amazing Victor Porof has landed an obscene number of patches in the last few weeks, with many fixes and tweaks for the debugger frontend. Of those I'd like to highlight the new functionality to search for variables in the current scope chain while the debugger is paused. Prepend your search with a star to search in the variables view. When you deal with large objects with long scope chains, finding the variable you are looking for can be like searching for a needle in a haystack. Now it's a piece of cake.
Searching for variables
Searching for variables
And last, but certainly not least, chrome debugging support has appeared in Nightly this past weekend! This will make debugging add-ons or Firefox itself way easier than ever before. You will need to enable remote debuging (devtools.debugger.remote-enabled) and browser chrome debugging as well (devtools.chrome.enabled, the same pref you switch to get Scratchpad to run against chrome).

Chrome debugging preferences
Chrome debugging preferences
This will get you a nice new Browser Debugger menu item in the Web Developer menu, which launches a separate debugger process to inspect your browser instance.

Browser Debugger menu item
Browser Debugger menu item

There has never been a better time to dive into Firefox internals and become a valued contributor. Take a look at this bug, to see how simple debugging has just become. Help us make the web better, by improving the lives of more than 400 million users!

Friday, October 5, 2012

Debugging Firefox OS

A few months ago, long before the Firefox debugger had shipped, I had tried to see what it would take to get it to debug B2G, or as we call it now, Firefox OS. The hack proved successful and with time it grew into an important debugging target for us. I demoed it at JSConf last April, but at that time a lot of the debugger frontend functionality had not been available in nightlies. As of yesterday, however, nightly builds of Firefox can debug nightly builds of Firefox OS, both in the device and desktop versions. Let me give you a quick rundown of the necessary steps.

First of all you need to go to about:config on your desktop Firefox and turn devtools.debugger.remote-enabled to true. After restarting Firefox you will have a new Remote Debugger menu item in your Web Developer menu.

You need to change the same setting in Firefox OS as well, and that requires finding the prefs.js file. For desktop builds, this will be in gaia-repository/profile/prefs.js. For devices, you should connect it to the desktop through a USB cable, use adb shell to connect to the device, and find the name of the default profile in /data/b2g/mozilla/. The prefs.js file wil be in that subdirectory, which in my case is /data/b2g/mozilla/ngsweij3.default/prefs.js. You can get that file off the device using:

adb pull /data/b2g/mozilla/ngsweij3.default/prefs.js prefs.js
 
That will store a copy of that file in your current working directory. You need to modify this file and then send it back to the device with:

adb push prefs.js /data/b2g/mozilla/ngsweij3.default/prefs.js

The necessary changes to that file are the following two lines:

user_pref("devtools.debugger.remote-enabled", true);
user_pref("marionette.defaultPrefs.enabled", false);

They enable the debugger server and at the same time disable the Marionette server, to avoid a conflict that we haven’t resolved yet.

That is all that is necessary for the desktop Firefox OS case, but you need to do one more thing for debugging Firefox OS on the device. If you are going to debug over a USB connection (which will also provide helpful console logs via adb logcat) you will need to forward a local port to the device using adb:

adb forward tcp:6000 tcp:6000

Port number 6000 is the default and if you need to change it for some reason, you can do so with the following pref:

user_pref("devtools.debugger.remote-port", 7000);

Debugging over WiFi is also possible, although disabled by default, so you will need to change the following pref to do so:

user_pref("devtools.debugger.force-local", false);

In that case, you don’t have to do the port forwarding step, but you may change the port number in the same way.

In order for the new settings to take effect in the device you have to restart it with ‘adb reboot’.

That’s all folks! Now you just start your nightly Firefox and select the Remote Debugger menu item. A dialog will pop up asking for the remote address and port number to connect to. The defaults will work for the desktop Firefox OS or the device debugging-over-USB cases (unless you changed the port number of course!). If you opted for debugging over WiFi, you will need to provide the IP address of the device. You can find it by tapping on the connection name in the settings.

After the connection is established, you will see a list of the sources loaded on the device, giving you the option to inspect the code, set breakpoints, step through the execution or even modify the values of variables. Here is a screencast that shows the debugger in action:



A better introductory guide to debugging Firefox OS will be available soon on MDN. This is just the first step in supporting Firefox OS development with Firefox developer tools. Just around the corner are web console support and profiling, with more to follow in the near future. If you have issues or suggestions for these tools, please get in touch! Post a comment, file a bug or pop in #devtools for a chat. Let's make the web the best platform to develop on!

Friday, February 19, 2010

The Cloud Desktop


This was originally posted in the mynetworkfolders.com blog.

We live in a browser these days. E-mail, word-processing, spreadsheets, chat, are all occupying a browser window in front of me. Maybe not for everyone yet, but the trend is clear, and has been clear for quite some time now. This is a good thing. The Web of today bears little similarity to the Web of the millennium. It's fast, it's powerful and it's ubiquitous. A consequence of that evolution is the simplicity with which I can continue my work when leaving my Linux workstation at work and sit in front of my Mac at home. Since my applications are web-based, they are OS- and browser-agnostic. More importantly, my data are always there when I need them. Readily accessible from my desktop, laptop or mobile phone. I may keep local backups for archival purposes, but my master copies are always online.

Assuming this trend is indeed inescapable, one can't help but wonder: what are the applications that have not migrated to the cloud, yet? What kind of things would I like to do online, seamlessly, from every device I own? What are the barriers that make our current online experience less powerful than the desktop one?

One thing that we noticed was missing from the online desktop, was the... desktop! Yes, my spreadsheets are online. Sure, my pictures are online. Yes, I can upload arbitrary files in various storage services. But, I couldn't find a way to use a familiar file manager interface to work with my data in the cloud, as I do on my computer. This was the need we decided to fulfill with MyNetworkFolders.

MyNetworkFolders attempts to provide an answer to the question: how would my desktop look in the cloud? And even though we are nowhere near done yet, the results so far are exciting and very promising.

MyNetworkFolders offers a familiar file manager interface for my cloud storage needs, with advanced functionality and ease of use. Documents can be viewed, modified, searched or sent to the trash. They can be shared with other users or among the members of a group using flexible ACLs, or even be publicly accessible from the whole internet. They can be versioned for tracking changes more effectively. The service can be accessed from a variety of ways, including a web browser, a desktop client, a WebDAV network share or (really soon) a mobile phone. But most importantly, there is no vendor lock-in. There is a REST-like API available, battle-tested from all the above client implementations, giving everyone the opportunity to access his data in his own particular way. Or even get them out of our service altogether.

Oh, and one other thing. It's all based on open-source software. The core infrastructure, the various clients we have built, even API helpers in various programming languages, are all available for anyone and everyone to see, use and modify. Or maybe used to setup and run YourNetworkFolders, if you feel really ambitious.

If however you just want a true desktop environment, with unparalleled flexibility, and maybe also see how far the cloud desktop rabbit-hole goes, then come along. It's going to be an exciting ride.

Monday, December 7, 2009

Lessons from Startup Weekend

I had an exhausting but fun weekend at the Athens Startup Weekend a few days ago. Along with Christos I joined Yannis, Panagiotis Christakos and Babis Makrinikolas on the Newspeek project. When Yannis pitched the idea on Friday night, the main concept was to create a mobile phone application that would provide a better way to view news on the go. I don't believe it was very clear in his mind then, what would constitute a "better" experience, but after some chatting about it we all defined a few key aspects, which we refined later with lots of useful feedback and help from George. Surprisingly, for me at least, in only two days we managed to design, build and present a working prototype in front of the judges and the other teams. And even though the demo wasn't exactly on par with our accomplishments, I'm still amazed at what can be created in such a short time frame.
Newspeek, our product, had a server-side component that periodically collected news items from various news feeds, stored them and provided them to clients through a simple REST API. It also had an iPhone client that fetched the news items and presented them to the user in a way that respected the UI requirements and established UX norms for that device.

So, in the interest of informing future participants about what works and what doesn't work in Startup Weekend, here are the lessons I learned:

  1. If you plan to win, work on the business aspect, not on the technology. Personally, I didn't go to ASW with plans to create a startup, so I didn't care that much about winning. I mostly considered the event as a hackathon, and tried my best to end up with a working prototype. Other teams focused more on the business side of things, which is understandable, given the prize. Investors fund teams that have a good chance to return a profit, not the ones with cool technology and (mostly) working demos. Still, the small number of actual working prototypes was a disappointment for me. Even though the developers were the majority in the event, you obviously can't have too many of them in a Startup Weekend.
  2. For quick server-side prototyping and hosting, Google App Engine is your friend. Since everyone in the team had Java experience, we could have gone with a JavaEE solution and set up a dedicated server to host the site. But, since I've always wanted to try App Engine for Java and the service architecture mapped nicely to it, we tried a short experiment to see if it could fly. We built a stub service in just a few minutes, so we decided it was well worth it. Building our RESTful service was really fast, scalability was never a concern and the deployment solution was a godsend, since the hosting service provided for free by the event sponsors was evidently overloaded. We're definitely going to use it again for other projects.
  3. jQTouch rocks! Since our main deliverable would be an iPhone application, and there were only two of us who had ever built an iPhone application (of the Hello World variety), we knew we had a problem. Fortunately, I had followed the jQTouch development from a reasonable distance and had witnessed the good things people had to say, so I pitched the idea of a web application to the team and it was well received. iPhone applications built with web technologies and jQTouch can be almost indistinguishable from native ones. We all had some experience in building web applications, so the prospect of having a working prototype in only two days seemed within the realm of possibility again. The future option of packaging the application with PhoneGap and selling it in the App Store was also a bonus point for our modest business plan.
  4. For ad-hoc collaboration, Mercurial wins. Without time to set up central repositories, a DVCS was the obvious choice, and Mercurial has both bundles and a standalone server that make collaborative coding a breeze. If we had zeroconf/bonjour set up in all of our laptops, we would have used the zeroconf extension for dead easy machine lookup, but even without it things worked flawlessly.
  5. You can write code with a netbook. Since I haven't owned a laptop for the last three years, my only portable computer is an Asus EEE PC 901 running Linux. Its original purpose was to allow me to browse the web from the comfort of my couch. Lately however, I'm finding myself using it to write software more than anything else. During the Startup Weekend it had constantly open Eclipse (for server-side code), Firefox (for JavaScript debugging), Chrome (for webkit rendering), gedit (for client-side code) and a terminal, without breaking a sweat.
  6. When demoing an iPhone application, whatever you do, don't sweat. Half-way through our presentation, tapping the buttons didn't work reliably all the time, so anxiety ensued. Since we couldn't make a proper presentation due to a missing cable, we opted for a live demo, wherein Yannis held the mic and made the presentation, and I posed as the bimbo that holds the product and clicks around. After a while we ended up both touching the screen, trying to make the bloody buttons click, which ensured the opposite effect. In retrospect, using a cloth occasionally would have made for a smoother demo, plus we could have slipped a joke in there, to keep the spirit up.
All in all it was an awesome experience, where we learned how far we can stretch ourselves, made new friends and caught up with old ones. Next year, I'll make sure I have a napkin, too.

Tuesday, July 7, 2009

GSS authentication

As I've described before, the GSS API is a REST-like interface for interacting with a GSS-based service, like Pithos. Using regular HTTP commands a client can upload, download, browse and modify files and folders stored in the GSS server. These interactions have two important properties: they store no client state to the server and they are not encrypted. I have already mentioned the most important benefits from the stateless architecture of the GSS protocol, namely scalability and loose coupling along the client-server boundary. In the same line of thought, SSL/TLS encryption of the transport was avoided for scalability reasons. Consequently, these two properties of the communication protocol, lead to another requirement: message authentication for each API call.


Since no session state is stored in the server, the client must authenticate each request as if it were the first one. Traditional web applications use an initial authentication interaction between client and server, that creates a unique session ID, which is transmitted with each subsequent request in that same session. While using this ID, the client does not need to authenticate again to the server. Stateless protocols, like WebDAV for instance, cannot rely on such an ID and have to transmit authentication data in each call. Ultimately the tradeoff is a minor increase in the message payload, in return for a big boost in scalability. The HTTP specification defines an Authorization header for use in such cases and WebDAV uses the HTTP Digest Access Authentication scheme. The GSS API uses a slight variation in that theme, blended with some ideas from OAuth request signing.

Essentially the standard HTTP Authorization header is populated with a concatenation of the username (for identifying the user making the request) and a HMAC-SHA1 signature of the request. The request signature is obtained by applying a secret authentication token to a concatenated string of the HTTP method name, the date and time of the request and the actual requested path. The GSS API page has all the details. The inclusion of the date and time helps thwart replay attacks using a previously sniffed signature. Furthermore, a separate header with timestamp information, X-GSS-Date, is used to thwart replay attacks with a full copy of the payload. The authentication token is issued securely by the server to the client and is the time-limited secret that is shared between the client and server. Since it is not the user password that is used as a shared secret, were the authentication token to be compromised, any ill effects would have been limited to the time period the token was valid. There are two ways for client applications to obtain the user's authentication token, and they are both described in detail in the API documentation.

In my experience, protocol descriptions are one thing and working code is a totally different one. In that spirit, I'm closing this post with a few tested implementations of the GSS API signature calculation, for client applications in different languages. Here is the method for signing a GSS API request in Java (full code here):


public static String sign(String httpMethod, String timestamp,
String path, String token) {
String input = httpMethod + timestamp + path;
String signed = null;

try {
System.err.println("Token:" + token);
// Get an HMAC-SHA1 key from the authentication token.
System.err.println("Input: " + input);
SecretKeySpec signingKey = new SecretKeySpec(
Base64.decodeBase64(token.getBytes()), "HmacSHA1");

// Get an HMAC-SHA1 Mac instance and initialize with the signing key.
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(signingKey);

// Compute the HMAC on the input data bytes.
byte[] rawMac = hmac.doFinal(input.getBytes());

// Do base 64 encoding.
signed = new String(Base64.encodeBase64(rawMac), "US-ASCII");

} catch (InvalidKeyException ikex) {
System.err.println("Fatal key exception: " + ikex.getMessage());
ikex.printStackTrace();
} catch (UnsupportedEncodingException ueex) {
System.err.println("Fatal encoding exception: "
+ ueex.getMessage());
} catch (NoSuchAlgorithmException nsaex) {
System.err.println("Fatal algorithm exception: "
+ nsaex.getMessage());
nsaex.printStackTrace();
}

if (signed == null)
System.exit(-1);
System.err.println("Signed: " + signed);
return signed;
}


Here is a method for signing GSS API requests in JavaScript, that uses the SHA-1 JavaScript implementation by Paul Johnston (full code here):


function sign(method, time, resource, token) {
var q = resource.indexOf('?');
var res = q == -1? resource: resource.substring(0, q);
var data = method + time + res;
// Use strict RFC compliance
b64pad = "=";
return b64_hmac_sha1(atob(token), data);
}

Here is a Tcl implementation by Alexios Zavras (full code here):


proc ::rest::_sign {id} {
variable $id
upvar 0 $id data
set str2sign ""
append str2sign $data(method)
append str2sign $data(date)
set idx [string first ? $data(path)]
if {$idx < 0} {
set str $data(path)
} else {
incr idx -1
set str [string range $data(path) 0 $idx]
}
# append str2sign [::util::url::encode $str]
append str2sign $str
puts "SIGN $str2sign"
set sig [::base64::encode [::sha1::hmac -bin -key $::GG(gsstoken) $str2sign]]
set data(signature) $sig
}

I'd love to show implementations of the signature calculation for other languages as well, but since my time is scarce these days, I could use some help here. If you've written one yourself and you'd like to share, leave a comment and I'll update this post, with proper attribution of course.

Thursday, April 23, 2009

An introduction to the GSS API

Application Programming Interface or API design is one of my favorite topics in programming, probably because it is both a science and an art. It is a science because there are widely accepted principles about how to design an API, but at the same time applying these principles within the constraints of a given programming language, requires the finesse of an experienced practicioner. Therefore it is with great pleasure that I'll try to explain the ins and outs of the GSS REST-like API, as promised before. As I've already mentioned, GSS is both the name of the source code project in Google Code, as well as the GRNET-sponsored service for the Greek research and academic network (although, it's official name after leaving the beta stage will be Pithos). Since anyone can use the open-source code to setup a GSS service, in this post I'll use generic examples, so anyone writing a client for the GRNET service should modify them accordingly.

When developing an application in a particular programming language, we are used to thinking about the APIs presented to us by the various libraries, which are invariably specified in that same language. For instance, for communicating with an HTTP server from a Java program we might use the HttpClient library API. This library presents a set of Java classes, interfaces and methods for interacting with web servers. These classes hide the underlying complexity of making the low-level HTTP protocol operations, allowing our mental process to remain constantly in a Java world. We could however interact with a web server without such a library, opting to implement the HTTP protocol interactions ourselves instead. Unfortunately, there is no such higher-level library for GSS yet, wrapping the low-level HTTP communications. Therefore this post will present a low-level API, in the sense that one has to make direct HTTP calls in his chosen programming language. The good news is that the following discussion is useful for programmers with any background, since there is support for the ubiquitus HTTP protocol in every modern programming language.

A RESTful API models its entities as resources. Resources are identified by Uniform Resource Identifiers, or URIs. There are four kinds of resources in GSS: files, folders, users & groups. These resources have a number of properties that contain various attributes. The API models these entities and their properties in the JSON format. There is also a fifth entity that is not modeled as a resource, but is important enough to warrant special mention: permissions.

Users · Users are the entities that represent the actual users of the system. They are used to login to the service and separate namespaces of files and folders. User entities have attributes like full name, e-mail, username, authentication token, creation/modification times, groups, etc. The URI of a user with username paul would be:

http://host.domain/gss/rest/paul/
The JSON representation of this user would be something like this:
{
"name": "Paul Smith",
"username": "paul",
"email": "paul@gmail.com",
"files": "http://hostname.domain/gss/rest/paul/files",
"trash": "http://hostname.domain/gss/rest/paul/trash",
"shared": "http://hostname.domain/gss/rest/paul/shared",
"others": "http://hostname.domain/gss/rest/paul/others",
"tags": "http://hostname.domain/gss/rest/paul/tags",
"groups": "http://hostname.domain/gss/rest/paul/groups",
"creationDate": 1223372769275,
"modificationDate": 1223372769275,
"quota": {
"totalFiles": 7,
"totalBytes": 429330,
"bytesRemaining": 10736988910
}
}


Groups · Groups are entities used to organize users for easier sharing of files and folders among peers. They can be used to facilitate sharing files to multiple users at once. Groups belong to the user who created them and cannot be shared. The URI of a group named work created by the user with username paul would be:
http://host.domain/gss/rest/paul/groups/work
The JSON representation of this group would be something like this:

[
"http://hostname.domain/gss/rest/paul/groups/work/tom",
"http://hostname.domain/gss/rest/paul/groups/work/jim",
"http://hostname.domain/gss/rest/paul/groups/work/mary"
]


Files · Files are the most basic resources in GSS. They represent actual operating system files from the client's computer that have been augmented with extra metadata for storage, retrieval and sharing purposes. Familiar metadata from modern file systems are also maintained in GSS, like file name, creation/modification times, creator, modifier, tags, permissions, etc. Furthermore, files can be versioned in GSS. Updating versioned files retains the previous versions, while updating an unversioned file replaces irrevocably the old file contents. The URI of a file named doc.txt located in the root folder of the user with username paul would be:
http://host.domain/gss/rest/paul/files/doc.txt
The JSON representation of the metadata in this file would be something like this:

{
"name": "doc.txt",
"creationDate": 1232449958563,
"createdBy": "paul",
"readForAll": true,
"modifiedBy": "paul",
"owner": "paul",
"modificationDate": 1232449944444,
"deleted": false,
"versioned": true,
"version": 1,
"size": 802,
"content": "text/plain",
"uri": "http://hostname.domain/gss/rest/paul/files/doc.txt",
"folder": {
"uri": "http://hostname/gss/rest/aaitest@uth.gr/files/",
"name": "Paul Smith"
},
"path": "/",
"tags": [
"work",
"personal"
],
"permissions": [
{
"modifyACL": true,
"write": true,
"read": true,
"user": "paul"
},
{
"modifyACL": false,
"write": true,
"read": true,
"group": "work"
}
]
}


Folders · Folders are resources that are used for grouping files. They represent the file system concept of folders or directories and can be used to mirror a client's computer file system on GSS. Familiar metadata from modern file systems are also maintained in GSS, like folder name, creation/modification times, creator, modifier, permissions, etc. The URI of a folder named documents located in the root folder of the user with username paul would be:
http://host.domain/gss/rest/paul/files/documents
The JSON representation of this folder would be something like this:

{
"name": "documents",
"owner": "paul",
"deleted": false,
"createdBy": "paul",
"creationDate": 1223372795825,
"modifiedBy": "paul",
"modificationDate": 1223372795825,
"parent": {
"uri": "http://hostname.domain/gss/rest/paul/files/",
"name": "Paul Smith"
},
"files": [
{
"name": "notes.txt",
"owner": "paul",
"creationDate": 1233758218866,
"deleted":false,
"size":4567,
"content": "text/plain",
"version": 1,
"uri": "http://hostname.domain/gss/rest/paul/files/documents/notes.txt",
"folder": {
"uri": "http://hostname.domain/gss/rest/paul/files/documents/",
"name": "documents"
},
"path": "/documents/"
}
],
"folders": [],
"permissions": [
{
"modifyACL": true,
"write": true,
"read": true,
"user": "paul"
},
{
"modifyACL": false,
"write": true,
"read": true,
"group": "work"
}
]
}

Working with these resources is accomplished by sending HTTP protocol requests to the resource URI with GET, HEAD, DELETE, POST, PUT methods. GET requests retrieve the resource representation, either the file contents, or the JSON representations for the resources specified above. HEAD requests for files return just the metadata of the file and DELETE requests remove the resource from the system. PUT requests upload files to the system from the client, while POST requests perform various modifications to the resources, like renaming, moving, copying, moving files to the trash, restoring them from the trash, creating folders and more. The operations are numerous and I hope to cover them in more detail in a future post.

One important aspect of every RESTful API is the use of URIs to allow the client to maintain a stateful conversation. For example, fetching the user URI would provide the files URI for fetching the available files and folders. Fetching the files URI would in turn return the URIs for the particular files and folders contained in the root folder (along with other folder properties). Returning to the parent of the current folder would entail following the URI contained in the parent property. This mechanism removes the state handling from the server and puts the burden on the client, providing excellent scalability for the service. Furthermore, since the URIs are treated opaquely by the client, the API allows client reuse across server deployments. A client can target multiple GSS services, as long as they speak the same RESTful API. Moreover, links from service A can refer to resources in service B without a problem (in the same authentication domain, e.g. the same Shibboleth federation). This is the same as using a single web browser to communicate with multiple web servers, by following links among them.

Monday, April 13, 2009

GSS architecture

Handling a large number of concurrent connections requires many servers. Not only because scaling vertically (throwing bigger hardware at the problem) is very costly, but also because even if an application can be designed to scale vertically, the underlying stack probably can not. Java applications for instance, like GSS, run on the JVM and although the latter is an excellent piece of engineering, using huge amounts of heap is not something it's tuned for. Big Iron servers with many cores and 20+ GB of RAM are usually running more than one JVM, since garbage collection is not all that efficient with huge heaps. And since running application instances with a 4-8 GB heap size can be done with cheap off-the-shelf hardware, why spend big bucks on Big Iron?

So having a large number of servers is a sane choice, but brings it's own set of problems. Unless one partitions users to servers (having all requests a particular user makes be delivered to the same server), all servers must have a consistent view of the system data, in order to deliver meaningful results. Assigning user requests to particular servers, usually requires expensive application layer load-balancers or customized application code on each server, so it would rarely be your first option. Having all servers work on the same data is a more tractable problem, since it can be solved by having the application state being replicated among server nodes. Usually, only a small part of the application state needs to be replicated, for each user, that is the part which concerns his current session. But even though session clustering solutions have been a well studied field and implementations abound, having no session to replicate is an even better option.

For GSS we have implemented a stateless architecture for the core server, that should provide us with good scalability in a very cost-effective manner. The most important part in this architecture is the REST-like API that moves part of the responsibility for session state maintenance to the client applications, effectively distributing the system load to more systems than the available server pool. Furthermore, client requests can be authenticated without requiring an SSL/TLS transport layer (even though it can be used if extra privacy is required), which would entail higher load on the application servers or require expensive load balancers. In the server side, API requests are being handled by servlets that enlist the services of stateless session beans, for easier transaction management. Our persistence story so far is JPA with a DBMS backing, plus high-speed SAN storage for the file contents. If or when this becomes a bottleneck, we have various contingency plans, depending on the actual characteristics of the load that will be observed.


The above image depicts the path user requests will travel along, while various nodes interact in order to serve them. A key element in this diagram is the number of different servers that can be found, effectively specializing in their own particular domain. Although the system can be deployed on a single physical server (and regularly is, for development and testing), consisting of a number of standalone sub-services instead of a big monolithic service is a boon to scalability.

This high-level overview of the GSS architecture should help those interested to find their way around the open-source codebase and explain some of the design decisions. But the most interesting part from a user's point of view would be the REST-like API, that allows one to take advantage of the service for scratching his own itch.

So that will be the subject of my next post.

Wednesday, April 8, 2009

Introducing GSS

During my recent work-induced blog hiatus, I've been working on a new software system, called GSS. I've been more than enjoying the ride so far and since we have released the code as open-source, I thought discussing some of the experience I've gained might be interesting to others as well.

GSS is a network, er grid, er I mean cloud service, for providing access to a file system on a remote storage space. It is the name of both a service (currently in beta) for the Greek research and academic community and the open source software used for it, that can also be used by others for deploying such services. It is similar in some ways to services like iDrive, DropBox and drop.io, but it can also be regarded as a more high-level Amazon S3. Its purpose is to let the desktop computer's file system meet the cloud. The familiar file system metaphors of files and folders are used to store information in a remote storage space, that can be accessed from a variety of user and system interfaces, from any place in the world that has an Internet connection. All usual file manager operations are supported and users can share their files with selected other users or groups, or even make them public. Currently there are four user interfaces available, a web-based application, a desktop client, a WebDAV interface and an iPhone web application, in various stages of development. Underlying these user interfaces is a common REST-like API that can be used to extend the service in new, unanticipated ways.


The main focus of this service was to provide the users of the Greek research and academic community with a free, large storage space that can be used to store, access, backup and share their work, from as many computer systems as they want. Since the available user base is close to half a million (although the expected users of the service are projected to the low ten thousands), we needed a scalable system, that would be able to accommodate high network traffic and a high storage capacity at the same time. A Java Enterprise Edition server coupled with a GWT-based web client and a stateless architecture were our solution. In future posts I will describe the system architecture with all the gory details. The exposed virtual file system features file versioning, trash bin support, access control lists, tagging, full text search and more.

All of these features are presented through an API for third party developers to create scripts, applications or even full blown services that will fulfill their own particular needs or serve other niches. This API has a REST-like design and though it will probably fail a formal RESTful definition, it sports many of the advantages of such architectures:

  • system resources such as users, groups, files and folders are represented by URIs
  • GET, HEAD, POST, PUT and DELETE methods on resources have the expected semantics
  • HTTP caching is explicitly supported via Last-Modified, ETag & If-* headers
  • resource formats for everything besides files are simple JSON representations
  • only authenticated requests are allowed, except for public resources

Users are authenticated through the GRNET Shibboleth infrastructure. User passwords are never transmitted to the GSS service. Instead GSS-issued authentication tokens are used by both client and server to sign the API requests after the initial user login. SSL transport can provide even stronger privacy guarantees, but it is not required, nor enabled by default.

The GSS code base is GPL-licensed and therefore anyone can use it as a starting point to implement his own file storage service. We have yet to provide binary downloads, due to the various dependencies, but the build instructions should be enough to get someone started. We are always interested in source or documentation patches, of course (did I mention it's open source?). Most importantly, the REST API will ensure that clients developed for one such service can be reused for every other one.

I will have much more to say about the API in a future post. In the meantime you can peruse the code and documentation, or even try it out yourself. I'd be very interested in any comments you might have.

Tuesday, October 7, 2008

Programming for fun

I've been in a hiatus from blogging lately, mainly because free time has been in short supply. It's not just the very busy days at work, nights have been even busier. Instead of churning out long blog posts, I've been banging on code instead, day and night. Unfortunately I only get paid for the code I write during the day, but surprisingly (or not) I enjoy the code I write at night the most.

I have written code for banks, multinational corporations, the kind of places where the phrase "professional dress code" is not used strictly in jokes. I've helped build software that was resilient, scalable, secure and intuitive, although granted, not all those at the same time. This was mainly Custom Enterprise Software, or to put it more plainly, Software That Runs On Computers At Work. So I thought I'd try a different angle in my spare time: write software that people use at work, or at home. Or at a coffee shop. Or at the airport. Or wherever they feel like using a computer, anyway. This is sometimes called End-User Software, or to put it in layman's terms, Software People May Actually Like. After trying out some ideas that didn't seem worthwhile, I discovered that some of my buddies had similar thoughts. This is how FireStatus was born.

FireStatus is a Firefox extension that aims to be a swiss army knife for dealing with various social networks, right from your browser, without visiting any particular website. Facebook, Twitter and FriendFeed are currently supported, but more are in the pipeline. For starters, it allows you to simultaneously update your status to all or some of these services, so that all your friends see it, no matter what they are using. The notion of a status that is occasionally updated is familiar to Twitter and Facebook users, since the text field that asks 'What are you doing?' is prominent in their user pages. FriendFeed does not have the notion of a status, but its users can post short (or long) messages, just like Twitter's. FriendFeed also allows posting links to web pages, accompanied with a short description, something that many Twitter and Facebook users have been doing by constructing status updates that start with the description text and are followed by an appended link, usually shortened.

FireStatus can ease the task of posting these messages or status updates, by being always available, instead of needing to have the service pages open and without a large memory footprint, like other similar applications, since it takes advantage of the fact that most people nowadays always have one browser open. I know I do. Come to think of it, I don't know anyone who uses computers that does not keep a browser running most of the time. At least untile the darned thing crashes, which fortunately is something I haven't experienced in Firefox for quite some time.


Posting a message or status update

Clicking on the FireStatus icon, pops up a small toolbar window just above the status bar and below the window document. It is similar to the Firefox findbar that pops up when one searches for text in a page, albeit slightly larger. That was a deliberate design decision that aimed to imitate the success in the usability of the findbar. Lots of little details like this one have been carefully thought out and occasionally debated at length among the team and our beta testers:
  • Enabling the spell checker in the status message field, for catching those typos when hastily typing a message.
  • Having the URL inclusion unchecked by default, while the shortening checked, since most posts do not include URLs (and it might be embarrassing if done inadvertently), but those that do usually want them short.
  • Adding a character counter to help guard against the maximum message length imposed by some services (e.g. Twitter).
  • Tightly placing the available services in a way that allows for an unambiguous selection.
  • Using the Escape and Enter keys as shortcuts for canceling and sending the update respectively.
As one reviewer in addons.mozilla.org so eloquently put it, "the simplicity & minimal design are the key components here".

Posting is not the whole story, though. These services provide continuous streams of updates from friends that we need to monitor. Sifting through the updates in every service, while very useful, becomes tedious after a while. It is like making a mental note to check your e-mail every once in a while for new messages. It's one way to do it for sure, but mail notifiers have been around for ages and provide more of a "live" experience.
FireStatus imitates their success in making e-mail conversations "alive", for conversations in the social network space. Every time a new incoming update is received, a notification popup appears, so I can continue using whatever application I was using, but being instantly aware of the news. Twitter notifications contain the name and the picture of the message author as well as the message sent. Low-priority or uninteresting messages can be just glanced at and then automatically dismissed, while important ones can be clicked on, so that the message can be viewed in the browser. FriendFeed notifications can be of various flavors, since FriendFeed aggregates updates from a large variety of online services.
Therefore FriendFeed updates display the service icon along with the author's name for quick identification of the type of update. Clicking on an interesting update opens a browser window to the link contained in the message. Facebook notifications currently contain new message counts, pokes and shares, but work for getting more data is underway.

Although the notifications appear instantaneous, as with e-mail notifications there is a polling process involved underneath. The polling frequency for each service can be separately tuned in the preferences window. The preference window can be opened by right-clicking on the FireStatus icon and selecting the appropriate option in the popup menu. Along with the time intervals between polling for updates, one can enable posting and/or receiving updates for the various services, as well as the authentication credentials where appropriate. For Facebook the user logs in in a Facebook-supplied browser window that pops up, similar to regular Facebook use. No credentials need to be stored separately by FireStatus. For FriendFeed the username and remote key have to be stored locally in the extension preferences. The remote key is not the same as the user password, but is provided by FriendFeed specifically for use by third-party applications, like ours. It can be found by clicking on the link displayed in the explanatory note. Twitter can work either way. If a username and password are entered in the preference window, they will be stored locally in the extension preferences and used for subsequent authentication. If, on the other hand, the fields are blank, FireStatus will consult the browser's Password Manager for any stored Twitter credentials. This will probably cause the master password dialog to pop up once, but the credentials will remain stored only in the Password Manager.

FireStatus preferences

Since we built this thing for our own personal use, pleasure and self-punishment, and as we don't plan to ever get rich out of it, we have released it from the beginning as open-source software through the permissive BSD license. You are most welcome to come by the project's home at Google Code, study the code, fix a bug (or two), help with the (embarrassingly outdated) documentation, contribute a review (otherwise it will remain an experimental extension forever) or just chat with us at the mailing list. Heck, if you feel like it, you can grab the whole code and use it in your own lucrative business and you don't owe us a dime.

With the shape the world economy currently is in, you probably couldn't afford it, anyway.

Creative Commons License Unless otherwise expressly stated, all original material in this weblog is licensed under a Creative Commons Attribution 3.0 License.